Passed
Pull Request — master (#98)
by Vinicius
03:24
created

TestMain.test_handle_link_liveness_disabled()   A

Complexity

Conditions 1

Size

Total Lines 21
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

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