Passed
Pull Request — master (#227)
by Vinicius
03:42
created

build.tests.unit.test_main   F

Complexity

Total Complexity 110

Size/Duplication

Total Lines 2194
Duplicated Lines 9.07 %

Test Coverage

Coverage 89.18%

Importance

Changes 0
Metric Value
eloc 1723
dl 199
loc 2194
ccs 1294
cts 1451
cp 0.8918
rs 0.8
c 0
b 0
f 0
wmc 110

85 Methods

Rating   Name   Duplication   Size   Complexity  
B TestMain.test_load_switch_attrs() 0 68 1
A TestMain.test_load_topology_fail_link() 0 19 1
A TestMain.test_load_topology_fail_switch() 0 19 1
A TestMain.test_load_topology_does_nothing() 0 11 1
A TestMain.test_handle_new_switch() 0 11 1
A TestMain.test_set_special_tags() 0 40 1
A TestMain.test_handle_link_up_intf_down() 0 18 1
A TestMain.test_set_tag_range_tag_error() 20 20 1
A TestMain.test_handle_on_interface_tags() 0 18 1
A TestMain.test_delete_interface() 0 10 1
A TestMain.test_notify_port_created() 0 9 1
A TestMain.test_disable_switch() 0 33 2
A TestMain.test_delete_tag_range_type_error() 0 15 1
A TestMain.test_notify_topology_update() 0 6 1
A TestMain.test_disable_link() 0 24 2
A TestMain.test_add_switch_metadata() 0 25 1
A TestMain.test_get_tag_ranges_by_intf_error() 0 9 1
A TestMain.test_get_switch_metadata() 0 17 1
A TestMain.test_get_link_from_interface() 0 14 1
B TestMain.test_get_topology() 0 51 1
A TestMain.test_add_links() 0 24 1
A TestMain.test_notify_link_status_change() 0 32 1
A TestMain.test_handle_link_down() 0 18 1
A TestMain.test_interface_link_up_unordered_event() 0 15 1
A TestMain.test_set_tag_range_not_found() 0 13 1
B TestMain.test_enable_link() 0 40 8
A TestMain.test_get_links_from_interfaces() 0 16 1
A TestMain.test_handle_interfaces_created() 0 17 1
A TestMain.test_interface_link_down_unordered_event() 0 15 1
A TestMain.test_handle_interface_down() 0 8 1
B TestMain.test_load_switch() 0 59 1
B TestMain.test_load_topology() 0 65 3
A TestMain.setup_method() 0 10 2
A TestMain.test_handle_link_down_not_active_last_status() 0 16 1
A TestMain.test_notify_switch_links_status() 0 22 1
A TestMain.test_delete_tag_range() 15 15 1
A TestMain.test_set_tag_range() 0 23 1
A TestMain.test_link_status_hook_link_up_timer() 0 13 1
A TestMain.test_interface_link_up() 0 27 1
A TestMain.test_add_link_metadata_wrong_format() 0 12 1
A TestMain.test_enable_switch() 0 23 1
A TestMain.test_delete_interface_metadata() 0 41 1
A TestMain.test_add_interface_metadata() 0 30 1
A TestMain.test_delete_tag_range_not_found() 14 14 1
A TestMain.test_handle_interface_created_inactive() 0 13 1
A TestMain.test_interruption_end() 39 39 1
B TestMain.test_enable_interfaces() 0 66 3
A TestMain.test_add_switch_metadata_wrong_format() 0 13 1
A TestMain.test_delete_link() 0 41 1
A TestMain.test_interruption_start() 39 39 1
A TestMain.test_notify_interface_link_status() 0 24 1
A TestMain.test_load_interfaces_tags_values() 0 24 1
A TestMain.test_notify_switch_enabled() 0 7 1
A TestMain.test_get_interface_metadata() 0 26 1
A TestMain.test_handle_link_up() 0 17 1
A TestMain.test_get_all_tag_ranges() 24 24 1
A TestMain.test_get_event_listeners() 0 23 1
A TestMain.test_delete_switch_metadata() 0 35 1
A TestMain.test_get_intf_usage() 0 24 1
A TestMain.test_notify_link_status() 0 10 1
A TestMain.test_handle_topo_controller_upsert_switch() 0 6 1
A TestMain.test_get_link_or_create() 0 20 1
A TestMain.test_interface_deleted() 0 6 1
A TestMain.test_notify_link_up_if_status() 0 26 1
A TestMain.test_delete_interface_api() 0 36 1
B TestMain.test_disable_interfaces() 0 70 3
A TestMain.test_set_tag_range_type_error() 22 22 1
A TestMain.test_add_link_metadata() 0 26 1
A TestMain.test_notify_switch_disabled() 0 7 1
A TestMain.test_get_link_metadata() 0 18 1
A TestMain.test_delete_link_metadata() 0 36 1
A TestMain.test_add_interface_metadata_wrong_format() 0 9 1
A TestMain.test_handle_link_down_not_active() 0 16 1
A TestMain.test_delete_switch() 0 48 3
A TestMain.test_interface_link_down() 0 16 1
A TestMain.test_notify_metadata_changes() 0 13 3
A TestMain.test_handle_connection_lost() 0 9 1
A TestMain.test_handle_link_liveness_disabled() 0 19 1
A TestMain.test_handle_interface_created() 0 11 1
A TestMain.test_get_flow_id_by_intf() 0 52 1
A TestMain.test_get_flows_by_switch() 0 15 2
A TestMain.test_get_tag_ranges_by_intf() 26 26 1
A TestMain.test_handle_lldp_status_updated() 0 20 1
B TestMain.test_load_link() 0 59 2
A TestMain.test_fail_load_link() 0 41 3

1 Function

Rating   Name   Duplication   Size   Complexity  
A test_handle_link_liveness_status() 0 19 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like build.tests.unit.test_main often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""Module to test the main napp file."""
2
# pylint: disable=import-error,no-name-in-module,wrong-import-order
3
# pylint: disable=import-outside-toplevel,attribute-defined-outside-init
4 1
import asyncio
5 1
import pytest
6 1
import time
7 1
from datetime import timedelta
8 1
from unittest.mock import MagicMock, create_autospec, patch, call, Mock
9 1
import tenacity
10 1
from kytos.core.common import EntityStatus
11 1
from kytos.core.helpers import now
12 1
from kytos.core.events import KytosEvent
13 1
from kytos.core.exceptions import (KytosSetTagRangeError,
14
                                   KytosTagtypeNotSupported)
15 1
from kytos.core.interface import Interface
16 1
from kytos.core.link import Link
17 1
from kytos.core.switch import Switch
18 1
from kytos.lib.helpers import (get_interface_mock, get_link_mock,
19
                               get_controller_mock, get_switch_mock,
20
                               get_test_client)
21 1
from napps.kytos.topology.exceptions import RestoreError
22
23
24 1
@pytest.mark.parametrize("liveness_status, status",
25
                         [("up", EntityStatus.UP),
26
                          ("down", EntityStatus.DOWN)])
27 1
def test_handle_link_liveness_status(liveness_status, status) -> None:
28
    """Test handle link liveness."""
29 1
    from napps.kytos.topology.main import Main
30 1
    napp = Main(get_controller_mock())
31 1
    napp.notify_topology_update = MagicMock()
32 1
    napp.notify_link_status_change = MagicMock()
33
34 1
    link = MagicMock(id="some_id", status=status)
35 1
    napp.handle_link_liveness_status(link, liveness_status)
36
37 1
    link.extend_metadata.assert_called_with({"liveness_status":
38
                                             liveness_status})
39 1
    assert napp.notify_topology_update.call_count == 1
40 1
    assert napp.notify_link_status_change.call_count == 1
41 1
    reason = f"liveness_{liveness_status}"
42 1
    napp.notify_link_status_change.assert_called_with(link, reason=reason)
43
44
45
# pylint: disable=too-many-public-methods
46 1
class TestMain:
47
    """Test the Main class."""
48
49
    # pylint: disable=too-many-public-methods, protected-access,C0302
50
51 1
    def setup_method(self):
52
        """Execute steps before each tests."""
53 1
        patch('kytos.core.helpers.run_on_thread', lambda x: x).start()
54
        # pylint: disable=import-outside-toplevel
55 1
        from napps.kytos.topology.main import Main
56 1
        Main.get_topo_controller = MagicMock()
57 1
        controller = get_controller_mock()
58 1
        self.napp = Main(controller)
59 1
        self.api_client = get_test_client(controller, self.napp)
60 1
        self.base_endpoint = 'kytos/topology/v3'
61
62 1
    def test_get_event_listeners(self):
63
        """Verify all event listeners registered."""
64 1
        expected_events = [
65
            'kytos/core.shutdown',
66
            'kytos/core.shutdown.kytos/topology',
67
            '.*.topo_controller.upsert_switch',
68
            '.*.of_lldp.network_status.updated',
69
            '.*.interface.is.nni',
70
            '.*.connection.lost',
71
            '.*.switch.interfaces.created',
72
            '.*.topology.switch.interface.created',
73
            '.*.switch.interface.deleted',
74
            '.*.switch.interface.link_down',
75
            '.*.switch.interface.link_up',
76
            '.*.switch.(new|reconnected)',
77
            'kytos/.*.liveness.(up|down|disabled)',
78
            '.*.switch.port.created',
79
            'kytos/topology.notify_link_up_if_status',
80
            'topology.interruption.(start|end)',
81
            'kytos/core.interface_tags',
82
        ]
83 1
        actual_events = self.napp.listeners()
84 1
        assert sorted(expected_events) == sorted(actual_events)
85
86 1
    def test_get_link_or_create(self):
87
        """Test _get_link_or_create."""
88 1
        dpid_a = "00:00:00:00:00:00:00:01"
89 1
        dpid_b = "00:00:00:00:00:00:00:02"
90 1
        mock_switch_a = get_switch_mock(dpid_a, 0x04)
91 1
        mock_switch_b = get_switch_mock(dpid_b, 0x04)
92 1
        mock_interface_a = get_interface_mock('s1-eth1', 1, mock_switch_a)
93 1
        mock_interface_b = get_interface_mock('s2-eth1', 1, mock_switch_b)
94 1
        mock_interface_a.id = dpid_a
95 1
        mock_interface_b.id = dpid_b
96
97 1
        link, created = self.napp._get_link_or_create(mock_interface_a,
98
                                                      mock_interface_b)
99 1
        assert created
100 1
        assert link.endpoint_a.id == dpid_a
101 1
        assert link.endpoint_b.id == dpid_b
102
103 1
        link, created = self.napp._get_link_or_create(mock_interface_a,
104
                                                      mock_interface_b)
105 1
        assert not created
106
107 1
    def test_get_link_from_interface(self):
108
        """Test _get_link_from_interface."""
109 1
        mock_switch_a = get_switch_mock("00:00:00:00:00:00:00:01", 0x04)
110 1
        mock_switch_b = get_switch_mock("00:00:00:00:00:00:00:02", 0x04)
111 1
        mock_interface_a = get_interface_mock('s1-eth1', 1, mock_switch_a)
112 1
        mock_interface_b = get_interface_mock('s2-eth1', 1, mock_switch_b)
113 1
        mock_interface_c = get_interface_mock('s2-eth1', 2, mock_switch_b)
114 1
        mock_link = get_link_mock(mock_interface_a, mock_interface_b)
115 1
        self.napp.links = {'0e2b5d7bc858b9f38db11b69': mock_link}
116 1
        response = self.napp._get_link_from_interface(mock_interface_a)
117 1
        assert response == mock_link
118
119 1
        response = self.napp._get_link_from_interface(mock_interface_c)
120 1
        assert not response
121
122 1
    async def test_get_topology(self):
123
        """Test get_topology."""
124 1
        dpid_a = "00:00:00:00:00:00:00:01"
125 1
        dpid_b = "00:00:00:00:00:00:00:02"
126 1
        expected = {
127
                      "topology": {
128
                        "switches": {
129
                          "00:00:00:00:00:00:00:01": {
130
                            "metadata": {
131
                              "lat": "0.0",
132
                              "lng": "-30.0"
133
                            }
134
                          },
135
                          "00:00:00:00:00:00:00:02": {
136
                            "metadata": {
137
                              "lat": "0.0",
138
                              "lng": "-30.0"
139
                            }
140
                          }
141
                        },
142
                        "links": {
143
                          "cf0f4071be4": {
144
                            "id": "cf0f4071be4"
145
                          }
146
                        }
147
                      }
148
                    }
149
150 1
        mock_switch_a = get_switch_mock(dpid_a, 0x04)
151 1
        mock_switch_b = get_switch_mock(dpid_b, 0x04)
152 1
        mock_interface_a = get_interface_mock('s1-eth1', 1, mock_switch_a)
153 1
        mock_interface_b = get_interface_mock('s2-eth1', 1, mock_switch_b)
154
155 1
        mock_link = get_link_mock(mock_interface_a, mock_interface_b)
156 1
        mock_link.id = 'cf0f4071be4'
157 1
        mock_switch_a.id = dpid_a
158 1
        mock_switch_a.as_dict.return_value = {'metadata': {'lat': '0.0',
159
                                              'lng': '-30.0'}}
160 1
        mock_switch_b.id = dpid_b
161 1
        mock_switch_b.as_dict.return_value = {'metadata': {'lat': '0.0',
162
                                              'lng': '-30.0'}}
163
164 1
        self.napp.controller.switches = {dpid_a: mock_switch_a,
165
                                         dpid_b: mock_switch_b}
166
167 1
        self.napp.links = {"cf0f4071be4": mock_link}
168 1
        mock_link.as_dict.return_value = {"id": "cf0f4071be4"}
169 1
        endpoint = f"{self.base_endpoint}/"
170 1
        response = await self.api_client.get(endpoint)
171 1
        assert response.status_code == 200
172 1
        assert response.json() == expected
173
174 1
    def test_load_topology(self):
175
        """Test load_topology."""
176 1
        mock_buffers_put = MagicMock()
177 1
        self.napp.controller.buffers.app.put = mock_buffers_put
178 1
        link_id = \
179
            'cf0f4071be426b3f745027f5d22bc61f8312ae86293c9b28e7e66015607a9260'
180 1
        dpid_a = '00:00:00:00:00:00:00:01'
181 1
        dpid_b = '00:00:00:00:00:00:00:02'
182 1
        topology = {
183
            "topology": {
184
                "links": {
185
                    link_id: {
186
                        "enabled": True,
187
                        "id": link_id,
188
                        "endpoint_a": {"id": f"{dpid_a}:2"},
189
                        "endpoint_b": {"id": f"{dpid_b}:2"},
190
                    }
191
                },
192
                "switches": {
193
                    dpid_a: {
194
                        "dpid": dpid_a,
195
                        "enabled": True,
196
                        "metadata": {},
197
                        "id": dpid_a,
198
                        "interfaces": {
199
                            f"{dpid_a}:2": {
200
                                "enabled": True,
201
                                "metadata": {},
202
                                "lldp": True,
203
                                "port_number": 2,
204
                                "name": "s1-eth2",
205
                            }
206
                        },
207
                    },
208
                    dpid_b: {
209
                        "dpid": dpid_b,
210
                        "enabled": True,
211
                        "metadata": {},
212
                        "id": dpid_b,
213
                        "interfaces": {
214
                            f"{dpid_b}:2": {
215
                                "enabled": True,
216
                                "metadata": {},
217
                                "lldp": True,
218
                                "port_number": 2,
219
                                "name": "s2-eth2",
220
                            }
221
                        },
222
                    },
223
                },
224
            }
225
        }
226 1
        switches_expected = [dpid_a, dpid_b]
227 1
        interfaces_expected = [f'{dpid_a}:2', f'{dpid_b}:2']
228 1
        links_expected = [link_id]
229 1
        self.napp.topo_controller.get_topology.return_value = topology
230 1
        self.napp.load_topology()
231 1
        assert switches_expected == list(self.napp.controller.switches.keys())
232 1
        interfaces = []
233 1
        for switch in self.napp.controller.switches.values():
234 1
            for iface in switch.interfaces.values():
235 1
                interfaces.append(iface.id)
236 1
        assert interfaces_expected == interfaces
237 1
        assert links_expected == list(self.napp.links.keys())
238 1
        assert mock_buffers_put.call_args[1] == {"timeout": 1}
239
240 1
    @patch('napps.kytos.topology.main.Main._load_switch')
241 1
    @patch('napps.kytos.topology.main.Main._load_link')
242 1
    def test_load_topology_does_nothing(self, *args):
243
        """Test _load_network_status doing nothing."""
244 1
        (mock_load_link, mock_load_switch) = args
245 1
        self.napp.topo_controller.get_topology.return_value = {
246
            "topology": {"switches": {}, "links": {}}
247
        }
248 1
        self.napp.topo_controller.load_topology()
249 1
        assert mock_load_link.call_count == 0
250 1
        assert mock_load_switch.call_count == 0
251
252 1
    @patch('napps.kytos.topology.main.Main._load_switch')
253 1
    @patch('napps.kytos.topology.main.log')
254 1
    def test_load_topology_fail_switch(self, *args):
255
        """Test load_topology failure in switch."""
256 1
        (mock_log, mock_load_switch) = args
257 1
        topology = {
258
            'topology': {
259
                'links': {},
260
                'switches': {
261
                    '1': {}
262
                }
263
            }
264
        }
265 1
        mock_log.error.return_value = True
266 1
        self.napp.topo_controller.get_topology.return_value = topology
267 1
        mock_load_switch.side_effect = AttributeError('xpto')
268 1
        self.napp.load_topology()
269 1
        error = 'Error loading switch: xpto'
270 1
        mock_log.error.assert_called_with(error)
271
272 1
    @patch('napps.kytos.topology.main.Main._load_link')
273 1
    @patch('napps.kytos.topology.main.log')
274 1
    def test_load_topology_fail_link(self, *args):
275
        """Test load_topology failure in link."""
276 1
        (mock_log, mock_load_link) = args
277 1
        topology = {
278
            'topology': {
279
                'switches': {},
280
                'links': {
281
                    '1': {}
282
                }
283
            }
284
        }
285 1
        mock_log.error.return_value = True
286 1
        self.napp.topo_controller.get_topology.return_value = topology
287 1
        mock_load_link.side_effect = AttributeError('xpto')
288 1
        self.napp.load_topology()
289 1
        error = 'Error loading link 1: xpto'
290 1
        mock_log.error.assert_called_with(error)
291
292 1
    @patch('napps.kytos.topology.main.Main.load_interfaces_tags_values')
293 1
    @patch('napps.kytos.topology.main.KytosEvent')
294 1
    def test_load_switch(self, *args):
295
        """Test _load_switch."""
296 1
        (mock_event, mock_load_tags) = args
297 1
        mock_buffers_put = MagicMock()
298 1
        self.napp.controller.buffers.app.put = mock_buffers_put
299 1
        dpid_a = "00:00:00:00:00:00:00:01"
300 1
        dpid_x = "00:00:00:00:00:00:00:XX"
301 1
        iface_a = f'{dpid_a}:1'
302 1
        switch_attrs = {
303
            'dpid': dpid_a,
304
            'enabled': True,
305
            'id': dpid_a,
306
            'metadata': {},
307
            'interfaces': {
308
                iface_a: {
309
                    'enabled': True,
310
                    'active': True,
311
                    'lldp': True,
312
                    'id': iface_a,
313
                    'switch': dpid_a,
314
                    'metadata': {},
315
                    'name': 's2-eth1',
316
                    'port_number': 1
317
                }
318
            }
319
        }
320 1
        self.napp._load_switch(dpid_a, switch_attrs)
321
322 1
        assert len(self.napp.controller.switches) == 1
323 1
        assert dpid_a in self.napp.controller.switches
324 1
        assert dpid_x not in self.napp.controller.switches
325 1
        switch = self.napp.controller.switches[dpid_a]
326 1
        interface_details = self.napp.topo_controller.get_interfaces_details
327 1
        interface_details.assert_called_once_with([iface_a])
328 1
        mock_load_tags.assert_called()
329
330 1
        assert switch.id == dpid_a
331 1
        assert switch.dpid == dpid_a
332 1
        assert switch.is_enabled()
333 1
        assert not switch.is_active()
334
335 1
        assert len(switch.interfaces) == 1
336 1
        assert 1 in switch.interfaces
337 1
        assert 2 not in switch.interfaces
338 1
        mock_event.assert_called()
339 1
        mock_buffers_put.assert_called()
340 1
        assert mock_buffers_put.call_args[1] == {"timeout": 1}
341
342 1
        interface = switch.interfaces[1]
343 1
        assert interface.id == iface_a
344 1
        assert interface.switch.id == dpid_a
345 1
        assert interface.port_number == 1
346 1
        assert interface.is_enabled()
347 1
        assert not interface.is_active()
348 1
        assert interface.lldp
349 1
        assert interface.uni
350 1
        assert not interface.nni
351
352 1
    def test_load_switch_attrs(self):
353
        """Test _load_switch."""
354 1
        dpid_b = "00:00:00:00:00:00:00:02"
355 1
        iface_b = f'{dpid_b}:1'
356 1
        switch_attrs = {
357
            "active": True,
358
            "connection": "127.0.0.1:43230",
359
            "data_path": "XX Human readable desc of dp",
360
            "dpid": "00:00:00:00:00:00:00:02",
361
            "enabled": False,
362
            "hardware": "Open vSwitch",
363
            "id": "00:00:00:00:00:00:00:02",
364
            "interfaces": {
365
                "00:00:00:00:00:00:00:02:1": {
366
                    "active": True,
367
                    "enabled": False,
368
                    "id": "00:00:00:00:00:00:00:02:1",
369
                    "link": "",
370
                    "lldp": False,
371
                    "mac": "de:58:c3:30:b7:b7",
372
                    "metadata": {},
373
                    "name": "s2-eth1",
374
                    "nni": False,
375
                    "port_number": 1,
376
                    "speed": 1250000000,
377
                    "switch": "00:00:00:00:00:00:00:02",
378
                    "type": "interface",
379
                    "uni": True
380
                },
381
            },
382
            "manufacturer": "Nicira, Inc.",
383
            "metadata": {},
384
            "name": "00:00:00:00:00:00:00:04",
385
            "ofp_version": "0x04",
386
            "serial": "XX serial number",
387
            "software": "2.10.7",
388
            "type": "switch"
389
        }
390
391 1
        assert len(self.napp.controller.switches) == 0
392 1
        self.napp._load_switch(dpid_b, switch_attrs)
393 1
        assert len(self.napp.controller.switches) == 1
394 1
        assert dpid_b in self.napp.controller.switches
395
396 1
        switch = self.napp.controller.switches[dpid_b]
397 1
        assert switch.id == dpid_b
398 1
        assert switch.dpid == dpid_b
399 1
        assert not switch.is_enabled()
400 1
        assert not switch.is_active()
401 1
        assert switch.description['manufacturer'] == 'Nicira, Inc.'
402 1
        assert switch.description['hardware'] == 'Open vSwitch'
403 1
        assert switch.description['software'] == '2.10.7'
404 1
        assert switch.description['serial'] == 'XX serial number'
405 1
        exp_data_path = 'XX Human readable desc of dp'
406 1
        assert switch.description['data_path'] == exp_data_path
407
408 1
        assert len(switch.interfaces) == 1
409 1
        assert 1 in switch.interfaces
410 1
        assert 2 not in switch.interfaces
411
412 1
        interface = switch.interfaces[1]
413 1
        assert interface.id == iface_b
414 1
        assert interface.switch.id == dpid_b
415 1
        assert interface.port_number == 1
416 1
        assert not interface.is_enabled()
417 1
        assert not interface.lldp
418 1
        assert interface.uni
419 1
        assert not interface.nni
420
421 1
    def test_load_interfaces_tags_values(self):
422
        """Test load_interfaces_tags_values."""
423 1
        dpid_a = "00:00:00:00:00:00:00:01"
424 1
        mock_switch_a = get_switch_mock(dpid_a, 0x04)
425 1
        mock_interface_a = get_interface_mock('s1-eth1', 1, mock_switch_a)
426 1
        mock_interface_a.id = dpid_a + ':1'
427 1
        mock_switch_a.interfaces = {1: mock_interface_a}
428 1
        ava_tags = {'vlan': [[10, 4095]]}
429 1
        tag_ranges = {'vlan': [[5, 4095]]}
430 1
        special_available_tags = {'vlan': ["untagged", "any"]}
431 1
        special_tags = {'vlan': ["untagged", "any"]}
432 1
        interface_details = [{
433
            "id": mock_interface_a.id,
434
            "available_tags": ava_tags,
435
            "tag_ranges": tag_ranges,
436
            "special_available_tags": special_available_tags,
437
            "special_tags": special_tags
438
        }]
439 1
        self.napp.load_interfaces_tags_values(mock_switch_a,
440
                                              interface_details)
441 1
        set_method = mock_interface_a.set_available_tags_tag_ranges
442 1
        set_method.assert_called_once_with(
443
            ava_tags, tag_ranges,
444
            special_available_tags, special_tags
445
        )
446
447 1
    def test_handle_on_interface_tags(self):
448
        """test_handle_on_interface_tags."""
449 1
        dpid_a = "00:00:00:00:00:00:00:01"
450 1
        available_tags = {'vlan': [[200, 3000]]}
451 1
        tag_ranges = {'vlan': [[20, 20], [200, 3000]]}
452 1
        special_available_tags = {'vlan': ["untagged", "any"]}
453 1
        mock_switch_a = get_switch_mock(dpid_a, 0x04)
454 1
        mock_interface_a = get_interface_mock('s1-eth1', 1, mock_switch_a)
455 1
        mock_interface_a.available_tags = available_tags
456 1
        mock_interface_a.tag_ranges = tag_ranges
457 1
        mock_interface_a.special_available_tags = special_available_tags
458 1
        mock_interface_a.special_tags = special_available_tags
459 1
        self.napp.handle_on_interface_tags(mock_interface_a)
460 1
        tp_controller = self.napp.topo_controller
461 1
        args = tp_controller.upsert_interface_details.call_args[0]
462 1
        assert args[0] == '00:00:00:00:00:00:00:01:1'
463 1
        assert args[1] == {'vlan': [[200, 3000]]}
464 1
        assert args[2] == {'vlan': [[20, 20], [200, 3000]]}
465
466 1
    def test_load_link(self):
467
        """Test _load_link."""
468 1
        dpid_a = "00:00:00:00:00:00:00:01"
469 1
        dpid_b = "00:00:00:00:00:00:00:02"
470 1
        link_id = '4d42dc08522'
471 1
        mock_switch_a = get_switch_mock(dpid_a, 0x04)
472 1
        mock_switch_b = get_switch_mock(dpid_b, 0x04)
473 1
        mock_interface_a = get_interface_mock('s1-eth1', 1, mock_switch_a)
474 1
        mock_interface_a.id = dpid_a + ':1'
475 1
        mock_interface_a.available_tags = [1, 2, 3]
476 1
        mock_interface_b = get_interface_mock('s2-eth1', 1, mock_switch_b)
477 1
        mock_interface_b.id = dpid_b + ':1'
478 1
        mock_interface_b.available_tags = [1, 2, 3]
479 1
        mock_switch_a.interfaces = {1: mock_interface_a}
480 1
        mock_switch_b.interfaces = {1: mock_interface_b}
481 1
        self.napp.controller.switches[dpid_a] = mock_switch_a
482 1
        self.napp.controller.switches[dpid_b] = mock_switch_b
483 1
        link_attrs = {
484
            'enabled': True,
485
            'id': link_id,
486
            'metadata': {},
487
            'endpoint_a': {
488
                'id': mock_interface_a.id
489
            },
490
            'endpoint_b': {
491
                'id': mock_interface_b.id
492
            }
493
        }
494
495 1
        self.napp._load_link(link_attrs)
496
497 1
        assert len(self.napp.links) == 1
498 1
        link = list(self.napp.links.values())[0]
499
500 1
        assert link.endpoint_a.id == mock_interface_a.id
501 1
        assert link.endpoint_b.id == mock_interface_b.id
502 1
        assert mock_interface_a.nni
503 1
        assert mock_interface_b.nni
504 1
        assert mock_interface_a.update_link.call_count == 1
505 1
        assert mock_interface_b.update_link.call_count == 1
506
507
        # test enable/disable
508 1
        link_id = '4d42dc08522'
509 1
        mock_interface_a = get_interface_mock('s1-eth1', 1, mock_switch_a)
510 1
        mock_interface_b = get_interface_mock('s2-eth1', 1, mock_switch_b)
511 1
        mock_link = get_link_mock(mock_interface_a, mock_interface_b)
512 1
        mock_link.id = link_id
513 1
        with patch('napps.kytos.topology.main.Main._get_link_or_create',
514
                   return_value=(mock_link, True)):
515
            # enable link
516 1
            link_attrs['enabled'] = True
517 1
            self.napp.links = {link_id: mock_link}
518 1
            self.napp._load_link(link_attrs)
519 1
            assert mock_link.enable.call_count == 1
520
            # disable link
521 1
            link_attrs['enabled'] = False
522 1
            self.napp.links = {link_id: mock_link}
523 1
            self.napp._load_link(link_attrs)
524 1
            assert mock_link.disable.call_count == 1
525
526 1
    @patch('napps.kytos.topology.main.Main._get_link_or_create')
527 1
    def test_fail_load_link(self, get_link_or_create_mock):
528
        """Test fail load_link."""
529 1
        dpid_a = '00:00:00:00:00:00:00:01'
530 1
        dpid_b = '00:00:00:00:00:00:00:02'
531 1
        link_id = '4d42dc08522'
532 1
        mock_switch_a = get_switch_mock(dpid_a)
533 1
        mock_switch_b = get_switch_mock(dpid_b)
534 1
        mock_interface_a_1 = get_interface_mock('s1-eth1', 1, mock_switch_a)
535 1
        mock_interface_b_1 = get_interface_mock('s2-eth1', 1, mock_switch_b)
536 1
        mock_link = get_link_mock(mock_interface_a_1, mock_interface_b_1)
537 1
        mock_link.id = link_id
538 1
        self.napp.links = {link_id: mock_link}
539 1
        get_link_or_create_mock.return_value = mock_link
540
541 1
        link_attrs_fail = {
542
            'enabled': True,
543
            'id': link_id,
544
            'metadata': {},
545
            'endpoint_a': {
546
                'id': f"{dpid_a}:999",
547
            },
548
            'endpoint_b': {
549
                'id': f"{dpid_b}:999",
550
            }
551
        }
552 1
        with pytest.raises(RestoreError):
553 1
            self.napp._load_link(link_attrs_fail)
554
555 1
        link_attrs_fail = {
556
            'enabled': True,
557
            'id': link_id,
558
            'endpoint_a': {
559
                'id': f"{dpid_a}:1",
560
            },
561
            'endpoint_b': {
562
                'id': f"{dpid_b}:1",
563
            }
564
        }
565 1
        with pytest.raises(RestoreError):
566 1
            self.napp._load_link(link_attrs_fail)
567
568 1
    @patch('napps.kytos.topology.main.Main.notify_switch_links_status')
569 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
570 1
    async def test_enable_switch(self, mock_notify_topo, mock_sw_l_status):
571
        """Test enable_switch."""
572 1
        dpid = "00:00:00:00:00:00:00:01"
573 1
        mock_switch = get_switch_mock(dpid)
574 1
        self.napp.controller.switches = {dpid: mock_switch}
575
576 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}/enable"
577 1
        response = await self.api_client.post(endpoint)
578 1
        assert response.status_code == 201
579 1
        assert mock_switch.enable.call_count == 1
580 1
        self.napp.topo_controller.enable_switch.assert_called_once_with(dpid)
581 1
        mock_notify_topo.assert_called()
582 1
        mock_sw_l_status.assert_called()
583
584
        # fail case
585 1
        mock_switch.enable.call_count = 0
586 1
        dpid = "00:00:00:00:00:00:00:02"
587 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}/enable"
588 1
        response = await self.api_client.post(endpoint)
589
        assert response.status_code == 404
590
        assert mock_switch.enable.call_count == 0
591
592 1
    @patch('napps.kytos.topology.main.Main.notify_link_enabled_state')
593 1
    @patch('napps.kytos.topology.main.Main.notify_switch_links_status')
594 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
595 1
    async def test_disable_switch(self, *args):
596
        """Test disable_switch."""
597 1
        mock_notify_topo, mock_sw_l_status, mock_noti_link = args
598 1
        dpid = "00:00:00:00:00:00:00:01"
599 1
        mock_switch = get_switch_mock(dpid)
600 1
        interface = Mock()
601 1
        interface.link.is_enabled = lambda: True
602 1
        mock_switch.interfaces = {1: interface}
603 1
        self.napp.controller.switches = {dpid: mock_switch}
604
605 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}/disable"
606 1
        response = await self.api_client.post(endpoint)
607 1
        assert response.status_code == 201
608 1
        assert mock_switch.disable.call_count == 1
609 1
        assert mock_noti_link.call_count == 1
610 1
        assert mock_noti_link.call_args[0][0] == interface.link
611 1
        assert mock_noti_link.call_args[0][1] == "disabled"
612 1
        assert interface.link.disable.call_count == 1
613 1
        assert self.napp.topo_controller.bulk_disable_links.call_count == 1
614 1
        self.napp.topo_controller.disable_switch.assert_called_once_with(dpid)
615 1
        mock_notify_topo.assert_called()
616 1
        mock_sw_l_status.assert_called()
617
618
        # fail case
619 1
        mock_switch.disable.call_count = 0
620 1
        dpid = "00:00:00:00:00:00:00:02"
621 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}/disable"
622 1
        response = await self.api_client.post(endpoint)
623
        assert response.status_code == 404
624
        assert mock_switch.disable.call_count == 0
625
626 1
    async def test_get_switch_metadata(self):
627
        """Test get_switch_metadata."""
628 1
        dpid = "00:00:00:00:00:00:00:01"
629 1
        mock_switch = get_switch_mock(dpid)
630 1
        mock_switch.metadata = "A"
631 1
        self.napp.controller.switches = {dpid: mock_switch}
632
633 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}/metadata"
634 1
        response = await self.api_client.get(endpoint)
635 1
        assert response.status_code == 200
636 1
        assert response.json() == {"metadata": mock_switch.metadata}
637
638
        # fail case
639 1
        dpid = "00:00:00:00:00:00:00:02"
640 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}/metadata"
641 1
        response = await self.api_client.get(endpoint)
642
        assert response.status_code == 404
643
644 1
    @patch('napps.kytos.topology.main.Main.notify_metadata_changes')
645 1
    async def test_add_switch_metadata(
646
        self, mock_metadata_changes
647
    ):
648
        """Test add_switch_metadata."""
649 1
        self.napp.controller.loop = asyncio.get_running_loop()
650 1
        dpid = "00:00:00:00:00:00:00:01"
651 1
        mock_switch = get_switch_mock(dpid)
652 1
        self.napp.controller.switches = {dpid: mock_switch}
653 1
        payload = {"data": "A"}
654
655 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}/metadata"
656 1
        response = await self.api_client.post(endpoint, json=payload)
657 1
        assert response.status_code == 201
658
659 1
        mock_metadata_changes.assert_called()
660 1
        self.napp.topo_controller.add_switch_metadata.assert_called_once_with(
661
            dpid, payload
662
        )
663
664
        # fail case
665 1
        dpid = "00:00:00:00:00:00:00:02"
666 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}/metadata"
667 1
        response = await self.api_client.post(endpoint, json=payload)
668
        assert response.status_code == 404
669
670 1
    async def test_add_switch_metadata_wrong_format(self):
671
        """Test add_switch_metadata_wrong_format."""
672 1
        self.napp.controller.loop = asyncio.get_running_loop()
673 1
        dpid = "00:00:00:00:00:00:00:01"
674 1
        payload = 'A'
675
676 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}/metadata"
677 1
        response = await self.api_client.post(endpoint, json=payload)
678
        assert response.status_code == 400
679
680
        payload = None
681
        response = await self.api_client.post(endpoint, json=payload)
682
        assert response.status_code == 415
683
684 1
    @patch('napps.kytos.topology.main.Main.notify_metadata_changes')
685 1
    async def test_delete_switch_metadata(
686
        self, mock_metadata_changes
687
    ):
688
        """Test delete_switch_metadata."""
689 1
        self.napp.controller.loop = asyncio.get_running_loop()
690 1
        dpid = "00:00:00:00:00:00:00:01"
691 1
        mock_switch = get_switch_mock(dpid)
692 1
        mock_switch.metadata = {"A": "A"}
693 1
        self.napp.controller.switches = {dpid: mock_switch}
694
695 1
        key = "A"
696 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}/metadata/{key}"
697 1
        response = await self.api_client.delete(endpoint)
698
699 1
        assert response.status_code == 200
700 1
        assert mock_metadata_changes.call_count == 1
701 1
        del_key_mock = self.napp.topo_controller.delete_switch_metadata_key
702 1
        del_key_mock.assert_called_with(
703
            dpid, key
704
        )
705
706
        # 404, Metadata not found
707 1
        mock_switch.metadata = {}
708 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}/metadata/{key}"
709 1
        response = await self.api_client.delete(endpoint)
710
        assert response.status_code == 404
711
712
        # 404, Switch not found
713
        key = "A"
714
        dpid = "00:00:00:00:00:00:00:02"
715
        endpoint = f"{self.base_endpoint}/switches/{dpid}/metadata/{key}"
716
        response = await self.api_client.delete(endpoint)
717
        assert mock_metadata_changes.call_count == 1
718
        assert response.status_code == 404
719
720
    # pylint: disable=too-many-statements
721 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
722 1
    async def test_enable_interfaces(self, mock_notify_topo):
723
        """Test enable_interfaces."""
724 1
        dpid = '00:00:00:00:00:00:00:01'
725 1
        mock_switch = get_switch_mock(dpid)
726 1
        mock_interface_1 = get_interface_mock('s1-eth1', 1, mock_switch)
727 1
        mock_interface_1.link = Mock()
728 1
        mock_interface_1.link._enabled = True
729 1
        mock_interface_2 = get_interface_mock('s1-eth2', 2, mock_switch)
730 1
        mock_interface_2.link = Mock()
731 1
        mock_interface_2.link._enabled = False
732 1
        mock_switch.interfaces = {1: mock_interface_1, 2: mock_interface_2}
733
734
        # Switch not found
735 1
        interface_id = '00:00:00:00:00:00:00:01:1'
736 1
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/enable"
737 1
        response = await self.api_client.post(endpoint)
738
        assert response.status_code == 404
739
740
        # Switch not enabled
741 1
        mock_switch.is_enabled = lambda: False
742
        self.napp.controller.switches = {dpid: mock_switch}
743
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/enable"
744
        response = await self.api_client.post(endpoint)
745
        assert response.status_code == 409
746
747
        # Success
748 1
        mock_switch.is_enabled = lambda: True
749
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/enable"
750
        response = await self.api_client.post(endpoint)
751 1
        assert response.status_code == 200
752 1
        assert mock_interface_1.enable.call_count == 1
753 1
        assert mock_interface_2.enable.call_count == 0
754 1
        self.napp.topo_controller.enable_interface.assert_called_with(
755
            interface_id
756
        )
757 1
        mock_notify_topo.assert_called()
758
759 1
        mock_interface_1.enable.call_count = 0
760 1
        mock_interface_2.enable.call_count = 0
761 1
        endpoint = f"{self.base_endpoint}/interfaces/switch/{dpid}/enable"
762 1
        response = await self.api_client.post(endpoint)
763 1
        assert response.status_code == 200
764 1
        self.napp.topo_controller.upsert_switch.assert_called_with(
765
            mock_switch.id, mock_switch.as_dict()
766
        )
767 1
        assert mock_interface_1.enable.call_count == 1
768 1
        assert mock_interface_2.enable.call_count == 1
769
770
        # test interface not found
771 1
        interface_id = '00:00:00:00:00:00:00:01:3'
772 1
        mock_interface_1.enable.call_count = 0
773 1
        mock_interface_2.enable.call_count = 0
774 1
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/enable"
775 1
        response = await self.api_client.post(endpoint)
776
        assert response.status_code == 404
777
        assert mock_interface_1.enable.call_count == 0
778
        assert mock_interface_2.enable.call_count == 0
779
780
        # test switch not found
781
        dpid = '00:00:00:00:00:00:00:02'
782
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/enable"
783
        response = await self.api_client.post(endpoint)
784
        assert response.status_code == 404
785
        assert mock_interface_1.enable.call_count == 0
786
        assert mock_interface_2.enable.call_count == 0
787
788 1
    @patch('napps.kytos.topology.main.Main.notify_link_enabled_state')
789 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
790 1
    async def test_disable_interfaces(self, mock_notify_topo, mock_noti_link):
791
        """Test disable_interfaces."""
792 1
        interface_id = '00:00:00:00:00:00:00:01:1'
793 1
        dpid = '00:00:00:00:00:00:00:01'
794 1
        mock_switch = get_switch_mock(dpid)
795 1
        mock_interface_1 = get_interface_mock('s1-eth1', 1, mock_switch)
796 1
        mock_interface_1.link = Mock()
797 1
        mock_interface_1.link.is_enabled = lambda: True
798 1
        mock_interface_2 = get_interface_mock('s1-eth2', 2, mock_switch)
799 1
        mock_interface_2.link = Mock()
800 1
        mock_interface_2.link.is_enabled = lambda: False
801 1
        mock_switch.interfaces = {1: mock_interface_1, 2: mock_interface_2}
802 1
        self.napp.controller.switches = {dpid: mock_switch}
803
804 1
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/disable"
805 1
        response = await self.api_client.post(endpoint)
806 1
        assert response.status_code == 200
807
808 1
        self.napp.topo_controller.disable_interface.assert_called_with(
809
            interface_id
810
        )
811 1
        assert mock_interface_1.disable.call_count == 1
812 1
        assert mock_interface_2.disable.call_count == 0
813 1
        assert mock_interface_1.link.disable.call_count == 1
814 1
        assert mock_noti_link.call_count == 1
815 1
        assert mock_noti_link.call_args[0][0] == mock_interface_1.link
816 1
        assert mock_noti_link.call_args[0][1] == "disabled"
817 1
        assert self.napp.topo_controller.disable_interface.call_count == 1
818 1
        mock_notify_topo.assert_called()
819
820 1
        mock_interface_1.disable.call_count = 0
821 1
        mock_interface_2.disable.call_count = 0
822
823 1
        endpoint = f"{self.base_endpoint}/interfaces/switch/{dpid}/disable"
824 1
        response = await self.api_client.post(endpoint)
825 1
        assert response.status_code == 200
826
827 1
        self.napp.topo_controller.upsert_switch.assert_called_with(
828
            mock_switch.id, mock_switch.as_dict()
829
        )
830 1
        assert mock_interface_1.disable.call_count == 1
831 1
        assert mock_interface_1.link.disable.call_count == 2
832 1
        assert mock_interface_2.disable.call_count == 1
833 1
        assert mock_noti_link.call_count == 2
834 1
        assert mock_noti_link.call_args[0][0] == mock_interface_1.link
835 1
        assert mock_noti_link.call_args[0][1] == "disabled"
836 1
        bulk_controller = self.napp.topo_controller.bulk_disable_links
837 1
        assert bulk_controller.call_count == 1
838 1
        assert len(bulk_controller.call_args[0][0]) == 1
839
840
        # test interface not found
841 1
        interface_id = '00:00:00:00:00:00:00:01:3'
842 1
        mock_interface_1.disable.call_count = 0
843 1
        mock_interface_2.disable.call_count = 0
844 1
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/disable"
845 1
        response = await self.api_client.post(endpoint)
846
847
        assert response.status_code == 404
848
        assert mock_interface_1.disable.call_count == 0
849
        assert mock_interface_2.disable.call_count == 0
850
851
        # test switch not found
852
        dpid = '00:00:00:00:00:00:00:02'
853
        endpoint = f"{self.base_endpoint}/interfaces/switch/{dpid}/disable"
854
        response = await self.api_client.post(endpoint)
855
        assert response.status_code == 404
856
        assert mock_interface_1.disable.call_count == 0
857
        assert mock_interface_2.disable.call_count == 0
858
859 1
    async def test_get_interface_metadata(self):
860
        """Test get_interface_metada."""
861 1
        interface_id = '00:00:00:00:00:00:00:01:1'
862 1
        dpid = '00:00:00:00:00:00:00:01'
863 1
        mock_switch = get_switch_mock(dpid)
864 1
        mock_interface = get_interface_mock('s1-eth1', 1, mock_switch)
865 1
        mock_interface.metadata = {"A": "B"}
866 1
        mock_switch.interfaces = {1: mock_interface}
867 1
        self.napp.controller.switches = {dpid: mock_switch}
868
869 1
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/metadata"
870 1
        response = await self.api_client.get(endpoint)
871 1
        assert response.status_code == 200
872 1
        assert response.json() == {"metadata": mock_interface.metadata}
873
874
        # fail case switch not found
875 1
        interface_id = '00:00:00:00:00:00:00:02:1'
876 1
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/metadata"
877 1
        response = await self.api_client.get(endpoint)
878
        assert response.status_code == 404
879
880
        # fail case interface not found
881
        interface_id = '00:00:00:00:00:00:00:01:2'
882
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/metadata"
883
        response = await self.api_client.get(endpoint)
884
        assert response.status_code == 404
885
886 1
    @patch('napps.kytos.topology.main.Main.notify_metadata_changes')
887 1
    async def test_add_interface_metadata(
888
        self, mock_metadata_changes
889
    ):
890
        """Test add_interface_metadata."""
891 1
        self.napp.controller.loop = asyncio.get_running_loop()
892 1
        interface_id = '00:00:00:00:00:00:00:01:1'
893 1
        dpid = '00:00:00:00:00:00:00:01'
894 1
        mock_switch = get_switch_mock(dpid)
895 1
        mock_interface = get_interface_mock('s1-eth1', 1, mock_switch)
896 1
        mock_interface.metadata = {"metada": "A"}
897 1
        mock_switch.interfaces = {1: mock_interface}
898 1
        self.napp.controller.switches = {dpid: mock_switch}
899 1
        payload = {"metada": "A"}
900 1
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/metadata"
901 1
        response = await self.api_client.post(endpoint, json=payload)
902 1
        assert response.status_code == 201
903 1
        mock_metadata_changes.assert_called()
904
905
        # fail case switch not found
906 1
        interface_id = '00:00:00:00:00:00:00:02:1'
907 1
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/metadata"
908 1
        response = await self.api_client.post(endpoint, json=payload)
909
        assert response.status_code == 404
910
911
        # fail case interface not found
912
        interface_id = '00:00:00:00:00:00:00:01:2'
913
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/metadata"
914
        response = await self.api_client.post(endpoint, json=payload)
915
        assert response.status_code == 404
916
917 1
    async def test_add_interface_metadata_wrong_format(self):
918
        """Test add_interface_metadata_wrong_format."""
919 1
        self.napp.controller.loop = asyncio.get_running_loop()
920 1
        interface_id = "00:00:00:00:00:00:00:01:1"
921 1
        endpoint = f"{self.base_endpoint}/interfaces/{interface_id}/metadata"
922 1
        response = await self.api_client.post(endpoint, json='A')
923
        assert response.status_code == 400
924
        response = await self.api_client.post(endpoint, json=None)
925
        assert response.status_code == 415
926
927 1
    async def test_delete_interface_metadata(self):
928
        """Test delete_interface_metadata."""
929 1
        self.napp.controller.loop = asyncio.get_running_loop()
930 1
        interface_id = '00:00:00:00:00:00:00:01:1'
931 1
        dpid = '00:00:00:00:00:00:00:01'
932 1
        mock_switch = get_switch_mock(dpid)
933 1
        mock_interface = get_interface_mock('s1-eth1', 1, mock_switch)
934 1
        mock_interface.remove_metadata.side_effect = [True, False]
935 1
        mock_interface.metadata = {"A": "A"}
936 1
        mock_switch.interfaces = {1: mock_interface}
937 1
        self.napp.controller.switches = {'00:00:00:00:00:00:00:01':
938
                                         mock_switch}
939
940 1
        key = 'A'
941 1
        url = f"{self.base_endpoint}/interfaces/{interface_id}/metadata/{key}"
942 1
        response = await self.api_client.delete(url)
943 1
        assert response.status_code == 200
944
945 1
        del_key_mock = self.napp.topo_controller.delete_interface_metadata_key
946 1
        del_key_mock.assert_called_once_with(interface_id, key)
947
948
        # fail case switch not found
949 1
        key = 'A'
950 1
        interface_id = '00:00:00:00:00:00:00:02:1'
951 1
        url = f"{self.base_endpoint}/interfaces/{interface_id}/metadata/{key}"
952 1
        response = await self.api_client.delete(url)
953
        assert response.status_code == 404
954
955
        # fail case interface not found
956
        key = 'A'
957
        interface_id = '00:00:00:00:00:00:00:01:2'
958
        url = f"{self.base_endpoint}/interfaces/{interface_id}/metadata/{key}"
959
        response = await self.api_client.delete(url)
960
        assert response.status_code == 404
961
962
        # fail case metadata not found
963
        key = 'B'
964
        interface_id = '00:00:00:00:00:00:00:01:1'
965
        url = f"{self.base_endpoint}/interfaces/{interface_id}/metadata/{key}"
966
        response = await self.api_client.delete(url)
967
        assert response.status_code == 404
968
969 1
    @patch('napps.kytos.topology.main.Main.notify_link_enabled_state')
970 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
971 1
    async def test_enable_link(self, mock_notify_topo, mock_noti_link):
972
        """Test enable_link."""
973 1
        mock_link = MagicMock(Link)
974 1
        link_id = "1"
975 1
        mock_link.id = link_id
976 1
        mock_link.is_enabled = lambda: False
977 1
        mock_link.endpoint_a = MagicMock(is_enabled=lambda: True)
978 1
        mock_link.endpoint_b = MagicMock(is_enabled=lambda: True)
979 1
        self.napp.links = {'1': mock_link}
980
981
        # 409, endpoint is/are disabled
982 1
        mock_link.endpoint_a.is_enabled = lambda: False
983 1
        mock_link.endpoint_b.is_enabled = lambda: False
984 1
        endpoint = f"{self.base_endpoint}/links/{link_id}/enable"
985 1
        response = await self.api_client.post(endpoint)
986
        assert response.status_code == 409
987
988 1
        mock_link.endpoint_a.is_enabled = lambda: True
989
        endpoint = f"{self.base_endpoint}/links/{link_id}/enable"
990
        response = await self.api_client.post(endpoint)
991
        assert response.status_code == 409
992
993
        # Success
994 1
        mock_link.endpoint_b.is_enabled = lambda: True
995
        endpoint = f"{self.base_endpoint}/links/{link_id}/enable"
996
        response = await self.api_client.post(endpoint)
997 1
        assert response.status_code == 201
998 1
        assert mock_noti_link.call_count == 1
999 1
        assert mock_noti_link.call_args[0][0] == mock_link
1000 1
        assert mock_noti_link.call_args[0][1] == "enabled"
1001 1
        mock_notify_topo.assert_called()
1002
1003
        # 404, link not found
1004 1
        link_id = "2"
1005 1
        endpoint = f"{self.base_endpoint}/links/{link_id}/enable"
1006 1
        response = await self.api_client.post(endpoint)
1007
        assert response.status_code == 404
1008
        assert mock_noti_link.call_count == 1
1009
1010 1
    @patch('napps.kytos.topology.main.Main.notify_link_enabled_state')
1011 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1012 1
    async def test_disable_link(self, mock_notify_topo, mock_notify):
1013
        """Test disable_link."""
1014 1
        mock_link = MagicMock(Link)
1015 1
        mock_link.is_enabled = lambda: True
1016 1
        self.napp.links = {'1': mock_link}
1017
1018 1
        link_id = "1"
1019 1
        endpoint = f"{self.base_endpoint}/links/{link_id}/disable"
1020 1
        response = await self.api_client.post(endpoint)
1021 1
        assert response.status_code == 201
1022 1
        assert mock_notify_topo.call_count == 1
1023 1
        assert mock_notify.call_count == 1
1024 1
        assert mock_notify.call_args[0][0] == mock_link
1025 1
        assert mock_notify.call_args[0][1] == "disabled"
1026 1
        assert mock_link.disable.call_count == 1
1027 1
        assert self.napp.topo_controller.disable_link.call_count == 1
1028
1029
        # fail case
1030 1
        link_id = "2"
1031 1
        endpoint = f"{self.base_endpoint}/links/{link_id}/disable"
1032 1
        response = await self.api_client.post(endpoint)
1033
        assert response.status_code == 404
1034
1035 1
    def test_handle_lldp_status_updated(self):
1036
        """Test handle_lldp_status_updated."""
1037 1
        event = MagicMock()
1038 1
        self.napp.controller.buffers.app.put = MagicMock()
1039
1040 1
        dpid_a = "00:00:00:00:00:00:00:01"
1041 1
        dpid_b = "00:00:00:00:00:00:00:02"
1042 1
        dpids = [dpid_a, dpid_b]
1043 1
        interface_ids = [f"{dpid}:1" for dpid in dpids]
1044
1045 1
        mock_switch_a = get_switch_mock(dpid_a, 0x04)
1046 1
        mock_switch_b = get_switch_mock(dpid_b, 0x04)
1047 1
        self.napp.controller.switches = {dpid_a: mock_switch_a,
1048
                                         dpid_b: mock_switch_b}
1049
1050 1
        event.content = {"interface_ids": interface_ids, "state": "disabled"}
1051 1
        self.napp.handle_lldp_status_updated(event)
1052
1053 1
        mock_put = self.napp.controller.buffers.app.put
1054 1
        assert mock_put.call_count == len(interface_ids)
1055
1056 1
    def test_handle_topo_controller_upsert_switch(self):
1057
        """Test handle_topo_controller_upsert_switch."""
1058 1
        event = MagicMock()
1059 1
        self.napp.handle_topo_controller_upsert_switch(event)
1060 1
        mock = self.napp.topo_controller.upsert_switch
1061 1
        mock.assert_called_with(event.id, event.as_dict())
1062
1063 1
    async def test_get_link_metadata(self):
1064
        """Test get_link_metadata."""
1065 1
        mock_link = MagicMock(Link)
1066 1
        mock_link.metadata = "A"
1067 1
        self.napp.links = {'1': mock_link}
1068 1
        msg_success = {"metadata": "A"}
1069
1070 1
        link_id = "1"
1071 1
        endpoint = f"{self.base_endpoint}/links/{link_id}/metadata"
1072 1
        response = await self.api_client.get(endpoint)
1073 1
        assert response.status_code == 200
1074 1
        assert msg_success == response.json()
1075
1076
        # fail case
1077 1
        link_id = "2"
1078 1
        endpoint = f"{self.base_endpoint}/links/{link_id}/metadata"
1079 1
        response = await self.api_client.get(endpoint)
1080
        assert response.status_code == 404
1081
1082 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1083 1
    @patch('napps.kytos.topology.main.Main.notify_metadata_changes')
1084 1
    async def test_add_link_metadata(
1085
        self,
1086
        mock_metadata_changes,
1087
        mock_topology_update
1088
    ):
1089
        """Test add_link_metadata."""
1090 1
        self.napp.controller.loop = asyncio.get_running_loop()
1091 1
        mock_link = MagicMock(Link)
1092 1
        mock_link.metadata = "A"
1093 1
        self.napp.links = {'1': mock_link}
1094 1
        payload = {"metadata": "A"}
1095 1
        link_id = 1
1096
1097 1
        endpoint = f"{self.base_endpoint}/links/{link_id}/metadata"
1098 1
        response = await self.api_client.post(endpoint, json=payload)
1099 1
        assert response.status_code == 201
1100 1
        mock_metadata_changes.assert_called()
1101 1
        mock_topology_update.assert_called()
1102
1103
        # fail case
1104 1
        link_id = 2
1105 1
        endpoint = f"{self.base_endpoint}/links/{link_id}/metadata"
1106 1
        response = await self.api_client.post(endpoint, json=payload)
1107
        assert response.status_code == 404
1108
1109 1
    async def test_add_link_metadata_wrong_format(self):
1110
        """Test add_link_metadata_wrong_format."""
1111 1
        self.napp.controller.loop = asyncio.get_running_loop()
1112 1
        link_id = 'cf0f4071be426b3f745027f5d22'
1113 1
        payload = "A"
1114 1
        endpoint = f"{self.base_endpoint}/links/{link_id}/metadata"
1115 1
        response = await self.api_client.post(endpoint, json=payload)
1116
        assert response.status_code == 400
1117
1118
        payload = None
1119
        response = await self.api_client.post(endpoint, json=payload)
1120
        assert response.status_code == 415
1121
1122 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1123 1
    @patch('napps.kytos.topology.main.Main.notify_metadata_changes')
1124 1
    async def test_delete_link_metadata(
1125
        self,
1126
        mock_metadata_changes,
1127
        mock_topology_update
1128
    ):
1129
        """Test delete_link_metadata."""
1130 1
        mock_link = MagicMock(Link)
1131 1
        mock_link.metadata = {"A": "A"}
1132 1
        mock_link.remove_metadata.side_effect = [True, False]
1133 1
        self.napp.links = {'1': mock_link}
1134
1135 1
        link_id = 1
1136 1
        key = 'A'
1137 1
        endpoint = f"{self.base_endpoint}/links/{link_id}/metadata/{key}"
1138 1
        response = await self.api_client.delete(endpoint)
1139 1
        assert response.status_code == 200
1140 1
        del_mock = self.napp.topo_controller.delete_link_metadata_key
1141 1
        del_mock.assert_called_once_with(mock_link.id, key)
1142 1
        mock_metadata_changes.assert_called()
1143 1
        mock_topology_update.assert_called()
1144
1145
        # fail case link not found
1146 1
        link_id = 2
1147 1
        key = 'A'
1148 1
        endpoint = f"{self.base_endpoint}/links/{link_id}/metadata/{key}"
1149 1
        response = await self.api_client.delete(endpoint)
1150
        assert response.status_code == 404
1151
1152
        # fail case metadata not found
1153
        link_id = 1
1154
        key = 'B'
1155
        endpoint = f"{self.base_endpoint}/links/{link_id}/metadata/{key}"
1156
        response = await self.api_client.delete(endpoint)
1157
        assert response.status_code == 404
1158
1159 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1160 1
    def test_handle_new_switch(self, mock_notify_topology_update):
1161
        """Test handle_new_switch."""
1162 1
        mock_event = MagicMock()
1163 1
        mock_switch = create_autospec(Switch)
1164 1
        mock_event.content['switch'] = mock_switch
1165 1
        self.napp.handle_new_switch(mock_event)
1166 1
        mock = self.napp.topo_controller.upsert_switch
1167 1
        mock.assert_called_once_with(mock_event.content['switch'].id,
1168
                                     mock_event.content['switch'].as_dict())
1169 1
        mock_notify_topology_update.assert_called()
1170
1171 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1172 1
    def test_handle_connection_lost(self, mock_notify_topology_update):
1173
        """Test handle connection_lost."""
1174 1
        mock_event = MagicMock()
1175 1
        mock_switch = create_autospec(Switch)
1176 1
        mock_switch.return_value = True
1177 1
        mock_event.content['source'] = mock_switch
1178 1
        self.napp.handle_connection_lost(mock_event)
1179 1
        mock_notify_topology_update.assert_called()
1180
1181 1
    @patch('napps.kytos.topology.main.Main.handle_interface_link_down')
1182 1
    @patch('napps.kytos.topology.main.Main.handle_interface_link_up')
1183 1
    def test_handle_interface_created(self, mock_link_up, mock_link_down):
1184
        """Test handle_interface_created."""
1185 1
        mock_event = MagicMock()
1186 1
        mock_interface = create_autospec(Interface)
1187 1
        mock_interface.id = "1"
1188 1
        mock_event.content = {'interface': mock_interface}
1189 1
        self.napp.handle_interface_created(mock_event)
1190 1
        mock_link_up.assert_called()
1191 1
        mock_link_down.assert_not_called()
1192
1193 1
    @patch('napps.kytos.topology.main.Main.handle_interface_link_down')
1194 1
    @patch('napps.kytos.topology.main.Main.handle_interface_link_up')
1195 1
    def test_handle_interface_created_inactive(self, mock_link_up,
1196
                                               mock_link_down):
1197
        """Test handle_interface_created inactive."""
1198 1
        mock_event = MagicMock()
1199 1
        mock_interface = create_autospec(Interface)
1200 1
        mock_interface.id = "1"
1201 1
        mock_event.content = {'interface': mock_interface}
1202 1
        mock_interface.is_active.return_value = False
1203 1
        self.napp.handle_interface_created(mock_event)
1204 1
        mock_link_up.assert_not_called()
1205 1
        mock_link_down.assert_called()
1206
1207 1
    def test_handle_interfaces_created(self):
1208
        """Test handle_interfaces_created."""
1209 1
        buffers_app_mock = MagicMock()
1210 1
        self.napp.controller.buffers.app = buffers_app_mock
1211 1
        mock_switch = create_autospec(Switch)
1212 1
        mock_event = MagicMock()
1213 1
        mock_interface = create_autospec(Interface)
1214 1
        mock_interface.id = "1"
1215 1
        mock_interface.switch = mock_switch
1216 1
        mock_interface_two = create_autospec(Interface)
1217 1
        mock_interface_two.id = "2"
1218 1
        mock_event.content = {'interfaces': [mock_interface,
1219
                              mock_interface_two]}
1220 1
        self.napp.handle_interfaces_created(mock_event)
1221 1
        upsert_mock = self.napp.topo_controller.upsert_switch
1222 1
        upsert_mock.assert_called_with(mock_switch.id, mock_switch.as_dict())
1223 1
        assert self.napp.controller.buffers.app.put.call_count == 2
1224
1225 1
    @patch('napps.kytos.topology.main.Main.handle_interface_link_down')
1226 1
    def test_handle_interface_down(self, mock_handle_interface_link_down):
1227
        """Test handle interface down."""
1228 1
        mock_event = MagicMock()
1229 1
        mock_interface = create_autospec(Interface)
1230 1
        mock_event.content['interface'] = mock_interface
1231 1
        self.napp.handle_interface_down(mock_event)
1232 1
        mock_handle_interface_link_down.assert_called()
1233
1234 1
    @patch('napps.kytos.topology.main.Main.handle_interface_down')
1235 1
    def test_interface_deleted(self, mock_handle_interface_link_down):
1236
        """Test interface deleted."""
1237 1
        mock_event = MagicMock()
1238 1
        self.napp.handle_interface_deleted(mock_event)
1239 1
        mock_handle_interface_link_down.assert_called()
1240
1241 1
    @patch('napps.kytos.topology.main.Main._get_link_from_interface')
1242 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1243 1
    def test_interface_link_up(self, *args):
1244
        """Test interface link_up."""
1245 1
        (mock_notify_topology_update,
1246
         mock_link_from_interface) = args
1247
1248 1
        tnow = time.time()
1249 1
        mock_interface_a = create_autospec(Interface)
1250 1
        mock_interface_a.is_active.return_value = False
1251 1
        mock_interface_b = create_autospec(Interface)
1252 1
        mock_interface_b.is_active.return_value = True
1253 1
        mock_link = create_autospec(Link)
1254 1
        mock_link.get_metadata.return_value = tnow
1255 1
        mock_link.is_active.side_effect = [False, True]
1256 1
        mock_link.endpoint_a = mock_interface_a
1257 1
        mock_link.endpoint_b = mock_interface_b
1258 1
        mock_link_from_interface.return_value = mock_link
1259 1
        mock_link.status = EntityStatus.UP
1260 1
        event = KytosEvent("kytos.of_core.switch.interface.down")
1261 1
        self.napp.handle_interface_link_up(mock_interface_a, event)
1262 1
        mock_notify_topology_update.assert_called()
1263 1
        mock_link.extend_metadata.assert_called()
1264 1
        mock_link.activate.assert_called()
1265 1
        assert self.napp.controller.buffers.app.put.call_count == 2
1266 1
        ev = "kytos/topology.notify_link_up_if_status"
1267 1
        assert self.napp.controller.buffers.app.put.call_args[0][0].name == ev
1268
1269 1
    @patch('napps.kytos.topology.main.Main._get_link_from_interface')
1270 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1271 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1272 1
    def test_interface_link_down(self, *args):
1273
        """Test interface link down."""
1274 1
        (mock_status_change, mock_topology_update,
1275
         mock_link_from_interface) = args
1276
1277 1
        mock_interface = create_autospec(Interface)
1278 1
        mock_link = create_autospec(Link)
1279 1
        mock_link.is_active.return_value = True
1280 1
        mock_link_from_interface.return_value = mock_link
1281 1
        event = KytosEvent("kytos.of_core.switch.interface.link_up")
1282 1
        self.napp.handle_interface_link_down(mock_interface, event)
1283 1
        mock_topology_update.assert_called()
1284 1
        mock_status_change.assert_called()
1285
1286 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1287 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1288 1
    def test_interface_link_down_unordered_event(self, *args):
1289
        """Test interface link down unordered event."""
1290 1
        (mock_status_change, mock_topology_update) = args
1291
1292 1
        mock_interface = create_autospec(Interface)
1293 1
        mock_interface.id = "1"
1294 1
        event_2 = KytosEvent("kytos.of_core.switch.interface.down")
1295 1
        event_1 = KytosEvent("kytos.of_core.switch.interface.up")
1296 1
        assert event_1.timestamp > event_2.timestamp
1297 1
        self.napp._intfs_updated_at[mock_interface.id] = event_1.timestamp
1298 1
        self.napp.handle_interface_link_down(mock_interface, event_2)
1299 1
        mock_topology_update.assert_not_called()
1300 1
        mock_status_change.assert_not_called()
1301
1302 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1303 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1304 1
    def test_interface_link_up_unordered_event(self, *args):
1305
        """Test interface link up unordered event."""
1306 1
        (mock_status_change, mock_topology_update) = args
1307
1308 1
        mock_interface = create_autospec(Interface)
1309 1
        mock_interface.id = "1"
1310 1
        event_2 = KytosEvent("kytos.of_core.switch.interface.up")
1311 1
        event_1 = KytosEvent("kytos.of_core.switch.interface.down")
1312 1
        assert event_1.timestamp > event_2.timestamp
1313 1
        self.napp._intfs_updated_at[mock_interface.id] = event_1.timestamp
1314 1
        self.napp.handle_interface_link_up(mock_interface, event_2)
1315 1
        mock_topology_update.assert_not_called()
1316 1
        mock_status_change.assert_not_called()
1317
1318 1
    @patch('napps.kytos.topology.main.Main._get_link_from_interface')
1319 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1320 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1321 1
    def test_handle_link_down(self, *args):
1322
        """Test interface link down."""
1323 1
        (mock_status_change, mock_topology_update,
1324
         mock_link_from_interface) = args
1325
1326 1
        mock_interface = create_autospec(Interface)
1327 1
        mock_link = create_autospec(Link)
1328 1
        mock_link.is_active.return_value = True
1329 1
        mock_link_from_interface.return_value = mock_link
1330 1
        self.napp.handle_link_down(mock_interface)
1331 1
        mock_interface.deactivate.assert_not_called()
1332 1
        mock_link.deactivate.assert_called()
1333 1
        mock_link.extend_metadata.assert_called()
1334 1
        assert mock_topology_update.call_count == 1
1335 1
        mock_status_change.assert_called()
1336
1337 1
    @patch('napps.kytos.topology.main.Main._get_link_from_interface')
1338 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1339 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1340 1
    def test_handle_link_down_not_active(self, *args):
1341
        """Test interface link down with link not active."""
1342 1
        (mock_status_change, mock_topology_update,
1343
         mock_link_from_interface) = args
1344
1345 1
        mock_interface = create_autospec(Interface)
1346 1
        mock_link = create_autospec(Link)
1347 1
        mock_link.is_active.return_value = False
1348 1
        mock_link_from_interface.return_value = mock_link
1349 1
        mock_link.get_metadata.return_value = False
1350 1
        self.napp.handle_link_down(mock_interface)
1351 1
        mock_topology_update.assert_called()
1352 1
        mock_status_change.assert_not_called()
1353
1354 1
    @patch('napps.kytos.topology.main.Main._get_link_from_interface')
1355 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1356 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1357 1
    def test_handle_link_down_not_active_last_status(self, *args):
1358
        """Test interface link down with link not active."""
1359 1
        (mock_status_change, mock_topology_update,
1360
         mock_link_from_interface) = args
1361
1362 1
        mock_interface = create_autospec(Interface)
1363 1
        mock_link = create_autospec(Link)
1364 1
        mock_link.is_active.return_value = False
1365 1
        mock_link_from_interface.return_value = mock_link
1366 1
        mock_link.get_metadata.return_value = True
1367 1
        self.napp.handle_link_down(mock_interface)
1368 1
        mock_topology_update.assert_called()
1369 1
        mock_status_change.assert_called()
1370
1371 1
    @patch('napps.kytos.topology.main.Main._get_link_from_interface')
1372 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1373 1
    def test_handle_link_up(self, *args):
1374
        """Test handle link up."""
1375 1
        (mock_notify_topology_update,
1376
         mock_link_from_interface) = args
1377
1378 1
        mock_interface = create_autospec(Interface)
1379 1
        mock_link = MagicMock(status=EntityStatus.UP)
1380 1
        mock_link.is_active.return_value = True
1381 1
        mock_link_from_interface.return_value = mock_link
1382 1
        self.napp.handle_link_up(mock_interface)
1383 1
        mock_interface.activate.assert_not_called()
1384 1
        mock_notify_topology_update.assert_called()
1385 1
        assert self.napp.controller.buffers.app.put.call_count == 2
1386 1
        ev = "kytos/topology.notify_link_up_if_status"
1387 1
        assert self.napp.controller.buffers.app.put.call_args[0][0].name == ev
1388
1389 1
    @patch('time.sleep')
1390 1
    @patch('napps.kytos.topology.main.Main._get_link_from_interface')
1391 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1392 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1393 1
    def test_handle_link_up_intf_down(self, *args):
1394
        """Test handle link up but one intf down."""
1395 1
        (mock_status_change, mock_topology_update,
1396
         mock_link_from_interface, _) = args
1397
1398 1
        mock_interface = create_autospec(Interface)
1399 1
        mock_link = MagicMock()
1400 1
        mock_link.endpoint_a.is_active.return_value = False
1401 1
        mock_link.is_active.return_value = False
1402 1
        mock_link_from_interface.return_value = mock_link
1403 1
        self.napp.handle_link_up(mock_interface)
1404 1
        mock_interface.activate.assert_not_called()
1405 1
        assert mock_topology_update.call_count == 1
1406 1
        mock_status_change.assert_not_called()
1407
1408 1
    @patch('napps.kytos.topology.main.Main._get_link_or_create')
1409 1
    @patch('napps.kytos.topology.main.Main.notify_link_up_if_status')
1410 1
    def test_add_links(self, *args):
1411
        """Test add_links."""
1412 1
        (mock_notify_link_up_if_status,
1413
         mock_get_link_or_create) = args
1414
1415 1
        mock_link = MagicMock()
1416 1
        mock_get_link_or_create.return_value = (mock_link, True)
1417 1
        mock_event = MagicMock()
1418 1
        mock_intf_a = MagicMock()
1419 1
        mock_intf_b = MagicMock()
1420 1
        mock_event.content = {
1421
            "interface_a": mock_intf_a,
1422
            "interface_b": mock_intf_b
1423
        }
1424 1
        self.napp.add_links(mock_event)
1425 1
        mock_link.extend_metadata.assert_called()
1426 1
        mock_get_link_or_create.assert_called()
1427 1
        mock_notify_link_up_if_status.assert_called()
1428 1
        mock_intf_a.update_link.assert_called()
1429 1
        mock_intf_b.update_link.assert_called()
1430 1
        mock_link.endpoint_a = mock_intf_a
1431 1
        mock_link.endpoint_b = mock_intf_b
1432
1433 1
    def test_notify_switch_enabled(self):
1434
        """Test notify switch enabled."""
1435 1
        dpid = "00:00:00:00:00:00:00:01"
1436 1
        mock_buffers_put = MagicMock()
1437 1
        self.napp.controller.buffers.app.put = mock_buffers_put
1438 1
        self.napp.notify_switch_enabled(dpid)
1439 1
        mock_buffers_put.assert_called()
1440
1441 1
    def test_notify_switch_disabled(self):
1442
        """Test notify switch disabled."""
1443 1
        dpid = "00:00:00:00:00:00:00:01"
1444 1
        mock_buffers_put = MagicMock()
1445 1
        self.napp.controller.buffers.app.put = mock_buffers_put
1446 1
        self.napp.notify_switch_disabled(dpid)
1447 1
        mock_buffers_put.assert_called()
1448
1449 1
    def test_notify_topology_update(self):
1450
        """Test notify_topology_update."""
1451 1
        mock_buffers_put = MagicMock()
1452 1
        self.napp.controller.buffers.app.put = mock_buffers_put
1453 1
        self.napp.notify_topology_update()
1454 1
        mock_buffers_put.assert_called()
1455
1456 1
    def test_notify_link_status_change(self):
1457
        """Test notify link status change."""
1458 1
        mock_buffers_put = MagicMock()
1459 1
        self.napp.controller.buffers.app.put = mock_buffers_put
1460 1
        mock_link = create_autospec(Link)
1461 1
        mock_link.id = 'test_link'
1462 1
        mock_link.status_reason = frozenset()
1463 1
        mock_link.status = EntityStatus.UP
1464
1465
        # Check when switching to up
1466 1
        self.napp.notify_link_status_change(mock_link, 'test')
1467 1
        assert mock_buffers_put.call_count == 1
1468 1
        args, _ = mock_buffers_put.call_args
1469 1
        event = args[0]
1470 1
        assert event.content['link'] is mock_link
1471 1
        assert event.content['reason'] == 'test'
1472 1
        assert event.name == 'kytos/topology.link_up'
1473
1474
        # Check result when no change
1475 1
        self.napp.notify_link_status_change(mock_link, 'test2')
1476 1
        assert mock_buffers_put.call_count == 1
1477
1478
        # Check when switching to down
1479 1
        mock_link.status_reason = frozenset({'disabled'})
1480 1
        mock_link.status = EntityStatus.DOWN
1481 1
        self.napp.notify_link_status_change(mock_link, 'test3')
1482 1
        assert mock_buffers_put.call_count == 2
1483 1
        args, _ = mock_buffers_put.call_args
1484 1
        event = args[0]
1485 1
        assert event.content['link'] is mock_link
1486 1
        assert event.content['reason'] == 'test3'
1487 1
        assert event.name == 'kytos/topology.link_down'
1488
1489 1
    def test_notify_metadata_changes(self):
1490
        """Test notify metadata changes."""
1491 1
        mock_buffers_put = MagicMock()
1492 1
        self.napp.controller.buffers.app.put = mock_buffers_put
1493 1
        count = 0
1494 1
        for spec in [Switch, Interface, Link]:
1495 1
            mock_obj = create_autospec(spec)
1496 1
            mock_obj.metadata = {"some_key": "some_value"}
1497 1
            self.napp.notify_metadata_changes(mock_obj, 'added')
1498 1
            assert mock_buffers_put.call_count == count+1
1499 1
            count += 1
1500 1
        with pytest.raises(ValueError):
1501 1
            self.napp.notify_metadata_changes(MagicMock(), 'added')
1502
1503 1
    def test_notify_port_created(self):
1504
        """Test notify port created."""
1505 1
        mock_buffers_put = MagicMock()
1506 1
        self.napp.controller.buffers.app.put = mock_buffers_put
1507 1
        event = KytosEvent("some_event")
1508 1
        expected_name = "kytos/topology.port.created"
1509 1
        self.napp.notify_port_created(event)
1510 1
        assert mock_buffers_put.call_count == 1
1511 1
        assert mock_buffers_put.call_args_list[0][0][0].name == expected_name
1512
1513 1
    def test_get_links_from_interfaces(self) -> None:
1514
        """Test get_links_from_interfaces."""
1515 1
        interfaces = [MagicMock(id=f"intf{n}") for n in range(4)]
1516 1
        links = {
1517
            "link1": MagicMock(id="link1",
1518
                               endpoint_a=interfaces[0],
1519
                               endpoint_b=interfaces[1]),
1520
            "link2": MagicMock(id="link2",
1521
                               endpoint_a=interfaces[2],
1522
                               endpoint_b=interfaces[3]),
1523
        }
1524 1
        self.napp.links = links
1525 1
        response = self.napp.get_links_from_interfaces(interfaces)
1526 1
        assert links == response
1527 1
        response = self.napp.get_links_from_interfaces(interfaces[:2])
1528 1
        assert response == {"link1": links["link1"]}
1529
1530 1
    def test_handle_link_liveness_disabled(self) -> None:
1531
        """Test handle_link_liveness_disabled."""
1532 1
        interfaces = [MagicMock(id=f"intf{n}") for n in range(4)]
1533 1
        links = {
1534
            "link1": MagicMock(id="link1",
1535
                               endpoint_a=interfaces[0],
1536
                               endpoint_b=interfaces[1]),
1537
            "link2": MagicMock(id="link2",
1538
                               endpoint_a=interfaces[2],
1539
                               endpoint_b=interfaces[3]),
1540
        }
1541 1
        self.napp.links = links
1542 1
        self.napp.notify_topology_update = MagicMock()
1543 1
        self.napp.notify_link_status_change = MagicMock()
1544
1545 1
        self.napp.handle_link_liveness_disabled(interfaces)
1546
1547 1
        assert self.napp.notify_topology_update.call_count == 1
1548 1
        assert self.napp.notify_link_status_change.call_count == len(links)
1549
1550 1
    def test_link_status_hook_link_up_timer(self) -> None:
1551
        """Test status hook link up timer."""
1552 1
        last_change = time.time() - self.napp.link_up_timer + 5
1553 1
        link = MagicMock(metadata={"last_status_change": last_change})
1554 1
        link.is_active.return_value = True
1555 1
        link.is_enabled.return_value = True
1556 1
        res = self.napp.link_status_hook_link_up_timer(link)
1557 1
        assert res == EntityStatus.DOWN
1558
1559 1
        last_change = time.time() - self.napp.link_up_timer
1560 1
        link.metadata["last_status_change"] = last_change
1561 1
        res = self.napp.link_status_hook_link_up_timer(link)
1562 1
        assert res is None
1563
1564 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1565 1
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
1566 1
    @patch('time.sleep')
1567 1
    def test_notify_link_up_if_status(
1568
        self,
1569
        mock_sleep,
1570
        mock_notify_topo,
1571
        mock_notify_link,
1572
    ) -> None:
1573
        """Test notify link up if status."""
1574
1575 1
        link = MagicMock(status=EntityStatus.UP)
1576 1
        link.get_metadata.return_value = now()
1577 1
        assert not self.napp.notify_link_up_if_status(link, "link up")
1578 1
        link.update_metadata.assert_not_called()
1579 1
        mock_notify_topo.assert_not_called()
1580 1
        mock_notify_link.assert_not_called()
1581
1582 1
        link = MagicMock(status=EntityStatus.UP)
1583 1
        link.get_metadata.return_value = now() - timedelta(seconds=60)
1584 1
        assert not self.napp.notify_link_up_if_status(link, "link up")
1585 1
        link.update_metadata.assert_called()
1586 1
        mock_notify_topo.assert_called()
1587 1
        mock_notify_link.assert_called()
1588
1589 1
        assert mock_sleep.call_count == 2
1590
1591 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1592 1
    def test_notify_switch_links_status(self, mock_notify_link_status_change):
1593
        """Test switch links notification when switch status change"""
1594 1
        buffers_app_mock = MagicMock()
1595 1
        self.napp.controller.buffers.app = buffers_app_mock
1596 1
        dpid = "00:00:00:00:00:00:00:01"
1597 1
        mock_switch = get_switch_mock(dpid)
1598 1
        link1 = MagicMock()
1599 1
        link1.endpoint_a.switch = mock_switch
1600 1
        self.napp.links = {1: link1}
1601
1602 1
        self.napp.notify_switch_links_status(mock_switch, "link enabled")
1603 1
        assert self.napp.controller.buffers.app.put.call_count == 1
1604
1605 1
        self.napp.notify_switch_links_status(mock_switch, "link disabled")
1606 1
        assert self.napp.controller.buffers.app.put.call_count == 1
1607 1
        assert mock_notify_link_status_change.call_count == 1
1608
1609
        # Without notification
1610 1
        link1.endpoint_a.switch = None
1611 1
        self.napp.notify_switch_links_status(mock_switch, "link enabled")
1612 1
        assert self.napp.controller.buffers.app.put.call_count == 1
1613
1614 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1615 1
    @patch('napps.kytos.topology.main.Main._get_link_from_interface')
1616 1
    def test_notify_interface_link_status(self, *args):
1617
        """Test interface links notification when enable"""
1618 1
        (mock_get_link_from_interface,
1619
         mock_notify_link_status_change) = args
1620 1
        buffers_app_mock = MagicMock()
1621 1
        self.napp.controller.buffers.app = buffers_app_mock
1622 1
        mock_link = MagicMock()
1623 1
        mock_get_link_from_interface.return_value = mock_link
1624 1
        self.napp.notify_interface_link_status(MagicMock(), "link enabled")
1625 1
        assert mock_get_link_from_interface.call_count == 1
1626 1
        assert self.napp.controller.buffers.app.put.call_count == 1
1627
1628 1
        self.napp.notify_interface_link_status(MagicMock(), "link disabled")
1629 1
        assert mock_get_link_from_interface.call_count == 2
1630 1
        assert mock_notify_link_status_change.call_count == 1
1631 1
        assert self.napp.controller.buffers.app.put.call_count == 1
1632
1633
        # Without notification
1634 1
        mock_get_link_from_interface.return_value = None
1635 1
        self.napp.notify_interface_link_status(MagicMock(), "link enabled")
1636 1
        assert mock_get_link_from_interface.call_count == 3
1637 1
        assert self.napp.controller.buffers.app.put.call_count == 1
1638
1639 1 View Code Duplication
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1640 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1641 1
    def test_interruption_start(
1642
        self,
1643
        mock_notify_link_status_change,
1644
        mock_notify_topology_update
1645
    ):
1646
        """Tests processing of received interruption start events."""
1647 1
        link_a = MagicMock()
1648 1
        link_b = MagicMock()
1649 1
        link_c = MagicMock()
1650 1
        self.napp.links = {
1651
            'link_a': link_a,
1652
            'link_b': link_b,
1653
            'link_c': link_c,
1654
        }
1655 1
        event = KytosEvent(
1656
            "topology.interruption.start",
1657
            {
1658
                'type': 'test_interruption',
1659
                'switches': [
1660
                ],
1661
                'interfaces': [
1662
                ],
1663
                'links': [
1664
                    'link_a',
1665
                    'link_c',
1666
                ],
1667
            }
1668
        )
1669 1
        self.napp.handle_interruption_start(event)
1670 1
        mock_notify_link_status_change.assert_has_calls(
1671
            [
1672
                call(link_a, 'test_interruption'),
1673
                call(link_c, 'test_interruption'),
1674
            ]
1675
        )
1676 1
        assert mock_notify_link_status_change.call_count == 2
1677 1
        mock_notify_topology_update.assert_called_once()
1678
1679 1 View Code Duplication
    @patch('napps.kytos.topology.main.Main.notify_topology_update')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1680 1
    @patch('napps.kytos.topology.main.Main.notify_link_status_change')
1681 1
    def test_interruption_end(
1682
        self,
1683
        mock_notify_link_status_change,
1684
        mock_notify_topology_update
1685
    ):
1686
        """Tests processing of received interruption end events."""
1687 1
        link_a = MagicMock()
1688 1
        link_b = MagicMock()
1689 1
        link_c = MagicMock()
1690 1
        self.napp.links = {
1691
            'link_a': link_a,
1692
            'link_b': link_b,
1693
            'link_c': link_c,
1694
        }
1695 1
        event = KytosEvent(
1696
            "topology.interruption.start",
1697
            {
1698
                'type': 'test_interruption',
1699
                'switches': [
1700
                ],
1701
                'interfaces': [
1702
                ],
1703
                'links': [
1704
                    'link_a',
1705
                    'link_c',
1706
                ],
1707
            }
1708
        )
1709 1
        self.napp.handle_interruption_end(event)
1710 1
        mock_notify_link_status_change.assert_has_calls(
1711
            [
1712
                call(link_a, 'test_interruption'),
1713
                call(link_c, 'test_interruption'),
1714
            ]
1715
        )
1716 1
        assert mock_notify_link_status_change.call_count == 2
1717 1
        mock_notify_topology_update.assert_called_once()
1718
1719 1
    async def test_set_tag_range(self):
1720
        """Test set_tag_range"""
1721 1
        self.napp.controller.loop = asyncio.get_running_loop()
1722 1
        interface_id = '00:00:00:00:00:00:00:01:1'
1723 1
        dpid = '00:00:00:00:00:00:00:01'
1724 1
        mock_switch = get_switch_mock(dpid)
1725 1
        mock_interface = get_interface_mock('s1-eth1', 1, mock_switch)
1726 1
        mock_interface.set_tag_ranges = MagicMock()
1727 1
        self.napp.handle_on_interface_tags = MagicMock()
1728 1
        self.napp.controller.get_interface_by_id = MagicMock()
1729 1
        self.napp.controller.get_interface_by_id.return_value = mock_interface
1730 1
        payload = {
1731
            "tag_type": "vlan",
1732
            "tag_ranges": [[20, 20], [200, 3000]]
1733
        }
1734 1
        url = f"{self.base_endpoint}/interfaces/{interface_id}/tag_ranges"
1735 1
        response = await self.api_client.post(url, json=payload)
1736 1
        assert response.status_code == 200
1737
1738 1
        args = mock_interface.set_tag_ranges.call_args[0]
1739 1
        assert args[0] == payload['tag_ranges']
1740 1
        assert args[1] == payload['tag_type']
1741 1
        assert self.napp.handle_on_interface_tags.call_count == 1
1742
1743 1
    async def test_set_tag_range_not_found(self):
1744
        """Test set_tag_range. Not found"""
1745 1
        self.napp.controller.loop = asyncio.get_running_loop()
1746 1
        interface_id = '00:00:00:00:00:00:00:01:1'
1747 1
        self.napp.controller.get_interface_by_id = MagicMock()
1748 1
        self.napp.controller.get_interface_by_id.return_value = None
1749 1
        payload = {
1750
            "tag_type": "vlan",
1751
            "tag_ranges": [[20, 20], [200, 3000]]
1752
        }
1753 1
        url = f"{self.base_endpoint}/interfaces/{interface_id}/tag_ranges"
1754 1
        response = await self.api_client.post(url, json=payload)
1755
        assert response.status_code == 404
1756
1757 1 View Code Duplication
    async def test_set_tag_range_tag_error(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1758
        """Test set_tag_range TagRangeError"""
1759 1
        self.napp.controller.loop = asyncio.get_running_loop()
1760 1
        interface_id = '00:00:00:00:00:00:00:01:1'
1761 1
        dpid = '00:00:00:00:00:00:00:01'
1762 1
        mock_switch = get_switch_mock(dpid)
1763 1
        mock_interface = get_interface_mock('s1-eth1', 1, mock_switch)
1764 1
        mock_interface.set_tag_ranges = MagicMock()
1765 1
        mock_interface.set_tag_ranges.side_effect = KytosSetTagRangeError("")
1766 1
        mock_interface.notify_interface_tags = MagicMock()
1767 1
        self.napp.controller.get_interface_by_id = MagicMock()
1768 1
        self.napp.controller.get_interface_by_id.return_value = mock_interface
1769 1
        payload = {
1770
            "tag_type": "vlan",
1771
            "tag_ranges": [[20, 20], [200, 3000]]
1772
        }
1773 1
        url = f"{self.base_endpoint}/interfaces/{interface_id}/tag_ranges"
1774 1
        response = await self.api_client.post(url, json=payload)
1775
        assert response.status_code == 400
1776
        assert mock_interface.notify_interface_tags.call_count == 0
1777
1778 1 View Code Duplication
    async def test_set_tag_range_type_error(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1779
        """Test set_tag_range TagRangeError"""
1780 1
        self.napp.controller.loop = asyncio.get_running_loop()
1781 1
        interface_id = '00:00:00:00:00:00:00:01:1'
1782 1
        dpid = '00:00:00:00:00:00:00:01'
1783 1
        mock_switch = get_switch_mock(dpid)
1784 1
        mock_interface = get_interface_mock('s1-eth1', 1, mock_switch)
1785 1
        mock_interface.set_tag_ranges = MagicMock()
1786 1
        mock_interface.set_tag_ranges.side_effect = KytosTagtypeNotSupported(
1787
            ""
1788
        )
1789 1
        self.napp.handle_on_interface_tags = MagicMock()
1790 1
        self.napp.controller.get_interface_by_id = MagicMock()
1791 1
        self.napp.controller.get_interface_by_id.return_value = mock_interface
1792 1
        payload = {
1793
            "tag_type": "wrong_tag_type",
1794
            "tag_ranges": [[20, 20], [200, 3000]]
1795
        }
1796 1
        url = f"{self.base_endpoint}/interfaces/{interface_id}/tag_ranges"
1797 1
        response = await self.api_client.post(url, json=payload)
1798
        assert response.status_code == 400
1799
        assert self.napp.handle_on_interface_tags.call_count == 0
1800
1801 1 View Code Duplication
    async def test_delete_tag_range(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1802
        """Test delete_tag_range"""
1803 1
        self.napp.controller.loop = asyncio.get_running_loop()
1804 1
        interface_id = '00:00:00:00:00:00:00:01:1'
1805 1
        dpid = '00:00:00:00:00:00:00:01'
1806 1
        mock_switch = get_switch_mock(dpid)
1807 1
        mock_interface = get_interface_mock('s1-eth1', 1, mock_switch)
1808 1
        mock_interface.remove_tag_ranges = MagicMock()
1809 1
        self.napp.handle_on_interface_tags = MagicMock()
1810 1
        self.napp.controller.get_interface_by_id = MagicMock()
1811 1
        self.napp.controller.get_interface_by_id.return_value = mock_interface
1812 1
        url = f"{self.base_endpoint}/interfaces/{interface_id}/tag_ranges"
1813 1
        response = await self.api_client.delete(url)
1814 1
        assert response.status_code == 200
1815 1
        assert mock_interface.remove_tag_ranges.call_count == 1
1816
1817 1 View Code Duplication
    async def test_delete_tag_range_not_found(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1818
        """Test delete_tag_range. Not found"""
1819 1
        self.napp.controller.loop = asyncio.get_running_loop()
1820 1
        interface_id = '00:00:00:00:00:00:00:01:1'
1821 1
        dpid = '00:00:00:00:00:00:00:01'
1822 1
        mock_switch = get_switch_mock(dpid)
1823 1
        mock_interface = get_interface_mock('s1-eth1', 1, mock_switch)
1824 1
        mock_interface.remove_tag_ranges = MagicMock()
1825 1
        self.napp.controller.get_interface_by_id = MagicMock()
1826 1
        self.napp.controller.get_interface_by_id.return_value = None
1827 1
        url = f"{self.base_endpoint}/interfaces/{interface_id}/tag_ranges"
1828 1
        response = await self.api_client.delete(url)
1829
        assert response.status_code == 404
1830
        assert mock_interface.remove_tag_ranges.call_count == 0
1831
1832 1
    async def test_delete_tag_range_type_error(self):
1833
        """Test delete_tag_range TagRangeError"""
1834 1
        self.napp.controller.loop = asyncio.get_running_loop()
1835 1
        interface_id = '00:00:00:00:00:00:00:01:1'
1836 1
        dpid = '00:00:00:00:00:00:00:01'
1837 1
        mock_switch = get_switch_mock(dpid)
1838 1
        mock_interface = get_interface_mock('s1-eth1', 1, mock_switch)
1839 1
        mock_interface.remove_tag_ranges = MagicMock()
1840 1
        remove_tag = mock_interface.remove_tag_ranges
1841 1
        remove_tag.side_effect = KytosTagtypeNotSupported("")
1842 1
        self.napp.controller.get_interface_by_id = MagicMock()
1843 1
        self.napp.controller.get_interface_by_id.return_value = mock_interface
1844 1
        url = f"{self.base_endpoint}/interfaces/{interface_id}/tag_ranges"
1845 1
        response = await self.api_client.delete(url)
1846
        assert response.status_code == 400
1847
1848 1 View Code Duplication
    async def test_get_all_tag_ranges(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1849
        """Test get_all_tag_ranges"""
1850 1
        self.napp.controller.loop = asyncio.get_running_loop()
1851 1
        dpid = '00:00:00:00:00:00:00:01'
1852 1
        switch = get_switch_mock(dpid)
1853 1
        interface = get_interface_mock('s1-eth1', 1, switch)
1854 1
        tags = {'vlan': [[1, 4095]]}
1855 1
        special_tags = {'vlan': ["vlan"]}
1856 1
        interface.tag_ranges = tags
1857 1
        interface.available_tags = tags
1858 1
        interface.special_available_tags = special_tags
1859 1
        interface.special_tags = special_tags
1860 1
        switch.interfaces = {1: interface}
1861 1
        self.napp.controller.switches = {dpid: switch}
1862 1
        url = f"{self.base_endpoint}/interfaces/tag_ranges"
1863 1
        response = await self.api_client.get(url)
1864 1
        expected = {dpid + ":1": {
1865
            'available_tags': tags,
1866
            'tag_ranges': tags,
1867
            'special_available_tags': special_tags,
1868
            'special_tags': special_tags
1869
        }}
1870 1
        assert response.status_code == 200
1871 1
        assert response.json() == expected
1872
1873 1 View Code Duplication
    async def test_get_tag_ranges_by_intf(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1874
        """Test get_tag_ranges_by_intf"""
1875 1
        self.napp.controller.loop = asyncio.get_running_loop()
1876 1
        dpid = '00:00:00:00:00:00:00:01'
1877 1
        switch = get_switch_mock(dpid)
1878 1
        interface = get_interface_mock('s1-eth1', 1, switch)
1879 1
        tags = {'vlan': [[1, 4095]]}
1880 1
        special_tags = {'vlan': ["vlan"]}
1881 1
        interface.tag_ranges = tags
1882 1
        interface.available_tags = tags
1883 1
        interface.special_available_tags = special_tags
1884 1
        interface.special_tags = special_tags
1885 1
        self.napp.controller.get_interface_by_id = MagicMock()
1886 1
        self.napp.controller.get_interface_by_id.return_value = interface
1887 1
        url = f"{self.base_endpoint}/interfaces/{dpid}:1/tag_ranges"
1888 1
        response = await self.api_client.get(url)
1889 1
        expected = {
1890
            '00:00:00:00:00:00:00:01:1': {
1891
                "available_tags": tags,
1892
                "tag_ranges": tags,
1893
                'special_available_tags': special_tags,
1894
                'special_tags': special_tags
1895
            }
1896
        }
1897 1
        assert response.status_code == 200
1898 1
        assert response.json() == expected
1899
1900 1
    async def test_get_tag_ranges_by_intf_error(self):
1901
        """Test get_tag_ranges_by_intf with NotFound"""
1902 1
        self.napp.controller.loop = asyncio.get_running_loop()
1903 1
        dpid = '00:00:00:00:00:00:00:01'
1904 1
        self.napp.controller.get_interface_by_id = MagicMock()
1905 1
        self.napp.controller.get_interface_by_id.return_value = None
1906 1
        url = f"{self.base_endpoint}/interfaces/{dpid}:1/tag_ranges"
1907 1
        response = await self.api_client.get(url)
1908
        assert response.status_code == 404
1909
1910 1
    async def test_set_special_tags(self):
1911
        """Test set_special_tags"""
1912 1
        self.napp.controller.loop = asyncio.get_running_loop()
1913 1
        interface_id = '00:00:00:00:00:00:00:01:1'
1914 1
        dpid = '00:00:00:00:00:00:00:01'
1915 1
        mock_switch = get_switch_mock(dpid)
1916 1
        mock_intf = get_interface_mock('s1-eth1', 1, mock_switch)
1917 1
        mock_intf.set_special_tags = MagicMock()
1918 1
        self.napp.handle_on_interface_tags = MagicMock()
1919 1
        self.napp.controller.get_interface_by_id = MagicMock()
1920 1
        self.napp.controller.get_interface_by_id.return_value = mock_intf
1921 1
        payload = {
1922
            "tag_type": "vlan",
1923
            "special_tags": ["untagged"],
1924
        }
1925 1
        url = f"{self.base_endpoint}/interfaces/{interface_id}/"\
1926
              "special_tags"
1927 1
        response = await self.api_client.post(url, json=payload)
1928 1
        assert response.status_code == 200
1929
1930 1
        args = mock_intf.set_special_tags.call_args[0]
1931 1
        assert args[0] == payload["tag_type"]
1932 1
        assert args[1] == payload['special_tags']
1933 1
        assert self.napp.handle_on_interface_tags.call_count == 1
1934
1935
        # KytosTagError
1936 1
        mock_intf.set_special_tags.side_effect = KytosTagtypeNotSupported("")
1937 1
        url = f"{self.base_endpoint}/interfaces/{interface_id}/"\
1938
              "special_tags"
1939 1
        response = await self.api_client.post(url, json=payload)
1940
        assert response.status_code == 400
1941
        assert self.napp.handle_on_interface_tags.call_count == 1
1942
1943
        # Interface Not Found
1944
        self.napp.controller.get_interface_by_id.return_value = None
1945
        url = f"{self.base_endpoint}/interfaces/{interface_id}/"\
1946
              "special_tags"
1947
        response = await self.api_client.post(url, json=payload)
1948
        assert response.status_code == 404
1949
        assert self.napp.handle_on_interface_tags.call_count == 1
1950
1951 1
    async def test_delete_link(self):
1952
        """Test delete_link"""
1953 1
        dpid_a = '00:00:00:00:00:00:00:01'
1954 1
        dpid_b = '00:00:00:00:00:00:00:02'
1955 1
        link_id = 'mock_link'
1956 1
        mock_switch_a = get_switch_mock(dpid_a)
1957 1
        mock_switch_b = get_switch_mock(dpid_b)
1958 1
        mock_interface_a = get_interface_mock('s1-eth1', 1, mock_switch_a)
1959 1
        mock_interface_b = get_interface_mock('s2-eth1', 1, mock_switch_b)
1960 1
        mock_link = get_link_mock(mock_interface_a, mock_interface_b)
1961 1
        mock_link.id = link_id
1962 1
        mock_link.status = EntityStatus.DISABLED
1963 1
        mock_interface_a.link = mock_link
1964 1
        mock_interface_b.link = mock_link
1965 1
        self.napp.links = {link_id: mock_link}
1966
1967 1
        call_count = self.napp.controller.buffers.app.put.call_count
1968 1
        endpoint = f"{self.base_endpoint}/links/{link_id}"
1969 1
        response = await self.api_client.delete(endpoint)
1970 1
        assert response.status_code == 200
1971 1
        assert self.napp.topo_controller.delete_link.call_count == 1
1972 1
        assert len(self.napp.links) == 0
1973 1
        call_count += 2
1974 1
        assert self.napp.controller.buffers.app.put.call_count == call_count
1975
1976
        # Link is up
1977 1
        self.napp.links = {link_id: mock_link}
1978 1
        mock_link.status = EntityStatus.UP
1979 1
        endpoint = f"{self.base_endpoint}/links/{link_id}"
1980 1
        response = await self.api_client.delete(endpoint)
1981
        assert response.status_code == 409
1982
        assert self.napp.topo_controller.delete_link.call_count == 1
1983
        assert self.napp.controller.buffers.app.put.call_count == call_count
1984
1985
        # Link does not exist
1986
        del self.napp.links[link_id]
1987
        endpoint = f"{self.base_endpoint}/links/{link_id}"
1988
        response = await self.api_client.delete(endpoint)
1989
        assert response.status_code == 404
1990
        assert self.napp.topo_controller.delete_link.call_count == 1
1991
        assert self.napp.controller.buffers.app.put.call_count == call_count
1992
1993 1
    @patch('napps.kytos.topology.main.Main.get_flows_by_switch')
1994 1
    async def test_delete_switch(self, mock_get):
1995
        """Test delete_switch"""
1996
        # Error 404 NotFound
1997 1
        dpid = '00:00:00:00:00:00:00:01'
1998 1
        endpoint = f"{self.base_endpoint}/switches/{dpid}"
1999 1
        response = await self.api_client.delete(endpoint)
2000
        assert response.status_code == 404, response
2001
2002
        # Error 409 Switch not disabled
2003
        mock_switch = get_switch_mock(dpid)
2004
        mock_switch.status = EntityStatus.UP
2005
        self.napp.controller.switches = {dpid: mock_switch}
2006
        endpoint = f"{self.base_endpoint}/switches/{dpid}"
2007
        response = await self.api_client.delete(endpoint)
2008
        assert response.status_code == 409, response
2009
2010
        # Error 409 Interface vlan is being used
2011 1
        mock_intf = MagicMock(all_tags_available=lambda: False)
2012
        mock_switch.interfaces = {1: mock_intf}
2013
        mock_switch.status = EntityStatus.DISABLED
2014
        endpoint = f"{self.base_endpoint}/switches/{dpid}"
2015
        response = await self.api_client.delete(endpoint)
2016
        assert response.status_code == 409, response
2017
2018
        # Error 409 Swith have links
2019 1
        mock_switch.interfaces[1].all_tags_available = lambda: True
2020
        mock_switch_2 = get_switch_mock("00:00:00:00:00:00:00:02")
2021
        mock_interface_a = get_interface_mock('s1-eth1', 1, mock_switch)
2022
        mock_interface_b = get_interface_mock('s2-eth1', 1, mock_switch_2)
2023
        mock_link = get_link_mock(mock_interface_a, mock_interface_b)
2024
        self.napp.links = {'0e2b5d7bc858b9f38db11b69': mock_link}
2025
        endpoint = f"{self.base_endpoint}/switches/{dpid}"
2026
        response = await self.api_client.delete(endpoint)
2027
        assert response.status_code == 409, response
2028
2029
        # Error 409 Switch has flows
2030
        mock_get.return_value = {dpid: {}}
2031
        endpoint = f"{self.base_endpoint}/switches/{dpid}"
2032
        response = await self.api_client.delete(endpoint)
2033
        assert response.status_code == 409, response
2034
2035
        # Success 202
2036
        mock_get.return_value = {}
2037
        self.napp.links = {}
2038
        endpoint = f"{self.base_endpoint}/switches/{dpid}"
2039
        response = await self.api_client.delete(endpoint)
2040 1
        assert response.status_code == 200, response
2041
2042 1
    def test_notify_link_status(self):
2043
        """Test notify_link_enabled_state"""
2044 1
        self.napp.controller.buffers.app.put.reset_mock()
2045 1
        link = Mock()
2046 1
        link.id = 'mock_link'
2047 1
        self.napp.notify_link_enabled_state(link, 'enabled')
2048 1
        assert self.napp.controller.buffers.app.put.call_count == 1
2049
2050 1
        self.napp.notify_link_enabled_state(link, 'disabled')
2051 1
        assert self.napp.controller.buffers.app.put.call_count == 2
2052
2053 1
    @patch('napps.kytos.topology.main.tenacity.nap.time')
2054 1
    @patch('httpx.get')
2055 1
    def test_get_flows_by_switch(self, mock_get, _):
2056
        """Test get_flows_by_switch"""
2057 1
        dpid = "00:01"
2058 1
        mock_get.return_value.status_code = 400
2059 1
        with pytest.raises(tenacity.RetryError):
2060 1
            self.napp.get_flows_by_switch(dpid)
2061
2062 1
        mock_get.return_value.status_code = 200
2063 1
        mock_get.return_value.is_server_error = False
2064 1
        expected = {dpid: "mocked_flows"}
2065 1
        mock_get.return_value.json.return_value = expected
2066 1
        actual = self.napp.get_flows_by_switch(dpid)
2067 1
        assert actual == "mocked_flows"
2068
2069 1
    @patch('napps.kytos.topology.main.Main.get_intf_usage')
2070 1
    @patch('napps.kytos.topology.main.Main._delete_interface')
2071 1
    async def test_delete_interface_api(self, mock_delete, mock_usage):
2072
        """Test delete interface API call"""
2073 1
        switch_id = "00:00:00:00:00:00:00:01"
2074 1
        intf_id = "00:00:00:00:00:00:00:01:1"
2075
2076
        # Error 400 Invalid interface id
2077 1
        endpoint = f"{self.base_endpoint}/interfaces/{intf_id}x"
2078 1
        response = await self.api_client.delete(endpoint)
2079
        assert response.status_code == 400, response
2080
2081
        # Error 404 Switch not found
2082
        endpoint = f"{self.base_endpoint}/interfaces/{intf_id}"
2083
        response = await self.api_client.delete(endpoint)
2084
        assert response.status_code == 404, response
2085
2086
        # Error 404 Interface not found
2087
        mock_switch = get_switch_mock(switch_id)
2088
        mock_switch.interfaces = {}
2089
        self.napp.controller.switches = {switch_id: mock_switch}
2090
        response = await self.api_client.delete(endpoint)
2091
        assert response.status_code == 404, response
2092
2093
        # Error 409 Interface is used
2094
        mock_switch.interfaces = {1: Mock()}
2095
        self.napp.controller.switches = {switch_id: mock_switch}
2096
        mock_usage.return_value = "It is enabled or active."
2097
        response = await self.api_client.delete(endpoint)
2098
        assert response.status_code == 409, response
2099
2100
        # Success
2101
        mock_usage.return_value = None
2102
        mock_delete.return_value = True
2103
        response = await self.api_client.delete(endpoint)
2104 1
        assert response.status_code == 200, response
2105
2106 1
    def test_get_intf_usage(self):
2107
        """Test get_intf_usage"""
2108 1
        switch_id = "00:00:00:00:00:00:00:01"
2109 1
        mock_switch = get_switch_mock(switch_id)
2110 1
        mock_intf = get_interface_mock('s1-eth1', 1, mock_switch)
2111
2112 1
        mock_intf.is_enabled.return_value = False
2113 1
        mock_intf.is_active.return_value = True
2114 1
        actual_usage = self.napp.get_intf_usage(mock_intf)
2115 1
        assert actual_usage == "It is enabled or active."
2116
2117 1
        mock_intf.is_active.return_value = False
2118 1
        self.napp._get_link_from_interface = MagicMock(return_value=Mock())
2119 1
        actual_usage = self.napp.get_intf_usage(mock_intf)
2120 1
        assert "It has a link," in actual_usage
2121
2122 1
        self.napp._get_link_from_interface.return_value = None
2123 1
        self.napp.get_flow_id_by_intf = MagicMock(return_value="mock_flow")
2124 1
        actual_usage = self.napp.get_intf_usage(mock_intf)
2125 1
        assert "There is a flow installed" in actual_usage
2126
2127 1
        self.napp.get_flow_id_by_intf.return_value = None
2128 1
        actual_usage = self.napp.get_intf_usage(mock_intf)
2129 1
        assert actual_usage is None
2130
2131 1
    @patch('napps.kytos.topology.main.Main.get_flows_by_switch')
2132 1
    def test_get_flow_id_by_intf(self, mock_flows):
2133
        """Test get_flow_id_by_intf"""
2134 1
        flows = [
2135
            {
2136
                "flow": {
2137
                    "match": {"in_port": 1, "dl_vlan": 200},
2138
                },
2139
                "flow_id": "flow_0",
2140
            },
2141
            {
2142
                "flow": {
2143
                    "actions": [{"action_type": "output", "port": 1}]
2144
                },
2145
                "flow_id": "flow_1",
2146
            },
2147
            {
2148
                "flow": {
2149
                    "instructions": [{
2150
                        "instruction_type": "apply_actions",
2151
                        "actions": [{"action_type": "output", "port": 1}]
2152
                    }]
2153
                },
2154
                "flow_id": "flow_2",
2155
            },
2156
            {
2157
                "flow": {
2158
                    "match": {"dl_src": "ee:ee:ee:ee:ee:02"},
2159
                },
2160
                "flow_id": "flow_3",
2161
            }
2162
        ]
2163
2164 1
        switch_id = "00:00:00:00:00:00:00:01"
2165 1
        mock_switch = get_switch_mock(switch_id)
2166 1
        mock_intf = get_interface_mock('s1-eth1', 1, mock_switch)
2167
2168 1
        mock_flows.return_value = [flows[0]]
2169 1
        flow_id = self.napp.get_flow_id_by_intf(mock_intf)
2170 1
        assert flow_id == flows[0]["flow_id"]
2171
2172 1
        mock_flows.return_value = [flows[1]]
2173 1
        flow_id = self.napp.get_flow_id_by_intf(mock_intf)
2174 1
        assert flow_id == flows[1]["flow_id"]
2175
2176 1
        mock_flows.return_value = [flows[2]]
2177 1
        flow_id = self.napp.get_flow_id_by_intf(mock_intf)
2178 1
        assert flow_id == flows[2]["flow_id"]
2179
2180 1
        mock_flows.return_value = [flows[3]]
2181 1
        flow_id = self.napp.get_flow_id_by_intf(mock_intf)
2182 1
        assert flow_id is None
2183
2184 1
    def test_delete_interface(self):
2185
        """Test _delete_interface"""
2186 1
        switch_id = "00:00:00:00:00:00:00:01"
2187 1
        mock_switch = get_switch_mock(switch_id)
2188 1
        mock_intf = get_interface_mock('s1-eth1', 1, mock_switch)
2189 1
        self.napp._delete_interface(mock_intf)
2190 1
        assert mock_switch.remove_interface.call_count == 1
2191 1
        assert self.napp.topo_controller.upsert_switch.call_count == 1
2192 1
        delete = self.napp.topo_controller.delete_interface_from_details
2193
        assert delete.call_count == 1
2194