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

test_handle_link_liveness_status()   A

Complexity

Conditions 1

Size

Total Lines 21
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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