Passed
Push — master ( 95e579...7054ad )
by Vinicius
05:34 queued 01:57
created

TestMain.test_handle_lldp_status_updated()   A

Complexity

Conditions 1

Size

Total Lines 20
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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