Test Failed
Pull Request — master (#129)
by Vinicius
09:59 queued 04:16
created

TestMain.test_verify_api_urls()   B

Complexity

Conditions 1

Size

Total Lines 47
Code Lines 45

Duplication

Lines 47
Ratio 100 %

Importance

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