Passed
Pull Request — master (#175)
by
unknown
02:50
created

lues()   A

Complexity

Conditions 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

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