Passed
Pull Request — master (#115)
by Vinicius
08:00 queued 04:59
created

TestMain.test_notify_interface_link_status()   A

Complexity

Conditions 1

Size

Total Lines 24
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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