Passed
Pull Request — master (#181)
by
unknown
06:49
created

TestMain.test_notify_interface_link_status()   A

Complexity

Conditions 1

Size

Total Lines 24
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 1

Importance

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