Passed
Pull Request — master (#84)
by Vinicius
02:53
created

TestMain.test_handle_new_switch()   A

Complexity

Conditions 1

Size

Total Lines 11
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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