Passed
Pull Request — master (#241)
by
unknown
03:21
created

TestEVC.test_should_deploy_case2()   A

Complexity

Conditions 1

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 12
nop 2
dl 0
loc 15
rs 9.8
c 0
b 0
f 0
1
"""Method to thest EVCDeploy class."""
2
import sys
3
from unittest import TestCase
4
from unittest.mock import MagicMock, Mock, patch, call
5
6
from kytos.core.common import EntityStatus
7
from kytos.core.exceptions import KytosNoTagAvailableError
8
from kytos.core.interface import Interface
9
from kytos.core.switch import Switch
10
from kytos.lib.helpers import get_controller_mock
11
12
# pylint: disable=wrong-import-position
13
sys.path.insert(0, "/var/lib/kytos/napps/..")
14
# pylint: enable=wrong-import-position
15
16
from napps.kytos.mef_eline.models import EVC, EVCDeploy, Path  # NOQA
17
from napps.kytos.mef_eline.settings import (
18
    MANAGER_URL,
19
    SDN_TRACE_CP_URL,
20
    EVPL_SB_PRIORITY,
21
    EPL_SB_PRIORITY
22
)  # NOQA
23
from napps.kytos.mef_eline.exceptions import FlowModException  # NOQA
24
from napps.kytos.mef_eline.tests.helpers import (
25
    get_link_mocked,
26
    get_uni_mocked,
27
)  # NOQA
28
29
30
# pylint: disable=too-many-public-methods, too-many-lines
31
class TestEVC(TestCase):
32
    """Tests to verify EVC class."""
33
34
    def setUp(self):
35
        attributes = {
36
            "controller": get_controller_mock(),
37
            "name": "circuit_for_tests",
38
            "uni_a": get_uni_mocked(is_valid=True),
39
            "uni_z": get_uni_mocked(is_valid=True),
40
        }
41
        self.evc_deploy = EVCDeploy(**attributes)
42
43
    def test_primary_links_zipped(self):
44
        """Test primary links zipped method."""
45
46
    @staticmethod
47
    @patch("napps.kytos.mef_eline.models.evc.log")
48
    def test_should_deploy_case1(log_mock):
49
        """Test should deploy method without primary links."""
50
        log_mock.debug.return_value = True
51
        attributes = {
52
            "controller": get_controller_mock(),
53
            "name": "custom_name",
54
            "uni_a": get_uni_mocked(is_valid=True),
55
            "uni_z": get_uni_mocked(is_valid=True),
56
        }
57
58
        evc = EVC(**attributes)
59
        evc.should_deploy()
60
        log_mock.debug.assert_called_with("Path is empty.")
61
62
    @patch("napps.kytos.mef_eline.models.evc.log")
63
    def test_should_deploy_case2(self, log_mock):
64
        """Test should deploy method with disable circuit."""
65
        log_mock.debug.return_value = True
66
        attributes = {
67
            "controller": get_controller_mock(),
68
            "name": "custom_name",
69
            "uni_a": get_uni_mocked(is_valid=True),
70
            "uni_z": get_uni_mocked(is_valid=True),
71
            "primary_links": [get_link_mocked(), get_link_mocked()],
72
        }
73
        evc = EVC(**attributes)
74
75
        self.assertFalse(evc.should_deploy(attributes["primary_links"]))
76
        log_mock.debug.assert_called_with(f"{evc} is disabled.")
77
78
    @patch("napps.kytos.mef_eline.models.evc.log")
79
    def test_should_deploy_case3(self, log_mock):
80
        """Test should deploy method with enabled and not active circuit."""
81
        log_mock.debug.return_value = True
82
        attributes = {
83
            "controller": get_controller_mock(),
84
            "name": "custom_name",
85
            "uni_a": get_uni_mocked(is_valid=True),
86
            "uni_z": get_uni_mocked(is_valid=True),
87
            "primary_links": [get_link_mocked(), get_link_mocked()],
88
            "enabled": True,
89
        }
90
        evc = EVC(**attributes)
91
        self.assertTrue(evc.should_deploy(attributes["primary_links"]))
92
        log_mock.debug.assert_called_with(f"{evc} will be deployed.")
93
94
    @patch("napps.kytos.mef_eline.models.evc.log")
95
    def test_should_deploy_case4(self, log_mock):
96
        """Test should deploy method with enabled and active circuit."""
97
        log_mock.debug.return_value = True
98
        attributes = {
99
            "controller": get_controller_mock(),
100
            "name": "custom_name",
101
            "uni_a": get_uni_mocked(is_valid=True),
102
            "uni_z": get_uni_mocked(is_valid=True),
103
            "primary_links": [get_link_mocked(), get_link_mocked()],
104
            "enabled": True,
105
            "active": True,
106
        }
107
        evc = EVC(**attributes)
108
        self.assertFalse(evc.should_deploy(attributes["primary_links"]))
109
110
    @patch("napps.kytos.mef_eline.models.evc.requests")
111
    def test_send_flow_mods_case1(self, requests_mock):
112
        """Test if you are sending flow_mods."""
113
        flow_mods = {"id": 20}
114
        switch = Mock(spec=Switch, id=1)
115
116
        response = MagicMock()
117
        response.status_code = 201
118
        requests_mock.post.return_value = response
119
120
        # pylint: disable=protected-access
121
        EVC._send_flow_mods(switch.id, flow_mods)
122
123
        expected_endpoint = f"{MANAGER_URL}/flows/{switch.id}"
124
        expected_data = {"flows": flow_mods, "force": False}
125
        self.assertEqual(requests_mock.post.call_count, 1)
126
        requests_mock.post.assert_called_once_with(
127
            expected_endpoint, json=expected_data
128
        )
129
130
    @patch("napps.kytos.mef_eline.models.evc.requests")
131
    def test_send_flow_mods_case2(self, requests_mock):
132
        """Test if you are sending flow_mods."""
133
        flow_mods = {"id": 20}
134
        switch = Mock(spec=Switch, id=1)
135
        response = MagicMock()
136
        response.status_code = 201
137
        requests_mock.post.return_value = response
138
139
        # pylint: disable=protected-access
140
        EVC._send_flow_mods(switch.id, flow_mods, command='delete', force=True)
141
142
        expected_endpoint = f"{MANAGER_URL}/delete/{switch.id}"
143
        expected_data = {"flows": flow_mods, "force": True}
144
        self.assertEqual(requests_mock.post.call_count, 1)
145
        requests_mock.post.assert_called_once_with(
146
            expected_endpoint, json=expected_data
147
        )
148
149
    @patch("napps.kytos.mef_eline.models.evc.requests")
150
    def test_send_flow_mods_error(self, requests_mock):
151
        """Test flow_manager call fails."""
152
        flow_mods = {"id": 20}
153
        switch = Mock(spec=Switch, id=1)
154
        response = MagicMock()
155
        response.status_code = 415
156
        requests_mock.post.return_value = response
157
158
        # pylint: disable=protected-access
159
        with self.assertRaises(FlowModException):
160
            EVC._send_flow_mods(
161
                switch.id,
162
                flow_mods,
163
                command='delete',
164
                force=True
165
            )
166
167
    def test_prepare_flow_mod(self):
168
        """Test prepare flow_mod method."""
169
        interface_a = Interface("eth0", 1, Mock(spec=Switch))
170
        interface_z = Interface("eth1", 3, Mock(spec=Switch))
171
        attributes = {
172
            "controller": get_controller_mock(),
173
            "name": "custom_name",
174
            "uni_a": get_uni_mocked(is_valid=True),
175
            "uni_z": get_uni_mocked(is_valid=True),
176
            "primary_links": [get_link_mocked(), get_link_mocked()],
177
            "enabled": True,
178
            "active": True,
179
        }
180
        evc = EVC(**attributes)
181
182
        # pylint: disable=protected-access
183
        flow_mod = evc._prepare_flow_mod(interface_a, interface_z)
184
        expected_flow_mod = {
185
            "match": {"in_port": interface_a.port_number},
186
            "cookie": evc.get_cookie(),
187
            "actions": [
188
                {"action_type": "output", "port": interface_z.port_number}
189
            ],
190
            "priority": EVPL_SB_PRIORITY,
191
        }
192
        self.assertEqual(expected_flow_mod, flow_mod)
193
194
    def test_prepare_pop_flow(self):
195
        """Test prepare pop flow  method."""
196
        attributes = {
197
            "controller": get_controller_mock(),
198
            "name": "custom_name",
199
            "uni_a": get_uni_mocked(interface_port=1, is_valid=True),
200
            "uni_z": get_uni_mocked(interface_port=2, is_valid=True),
201
        }
202
        evc = EVC(**attributes)
203
        interface_a = evc.uni_a.interface
204
        interface_z = evc.uni_z.interface
205
        in_vlan = 10
206
207
        # pylint: disable=protected-access
208
        flow_mod = evc._prepare_pop_flow(
209
            interface_a, interface_z, in_vlan
210
        )
211
212
        expected_flow_mod = {
213
            "match": {"in_port": interface_a.port_number, "dl_vlan": in_vlan},
214
            "cookie": evc.get_cookie(),
215
            "actions": [
216
                {"action_type": "pop_vlan"},
217
                {"action_type": "output", "port": interface_z.port_number},
218
            ],
219
            "priority": EVPL_SB_PRIORITY,
220
        }
221
        self.assertEqual(expected_flow_mod, flow_mod)
222
223
    def test_prepare_push_flow(self):
224
        """Test prepare push flow method."""
225
        attributes = {
226
            "controller": get_controller_mock(),
227
            "name": "custom_name",
228
            "uni_a": get_uni_mocked(interface_port=1, is_valid=True),
229
            "uni_z": get_uni_mocked(interface_port=2, is_valid=True),
230
        }
231
        evc = EVC(**attributes)
232
        interface_a = evc.uni_a.interface
233
        interface_z = evc.uni_z.interface
234
        out_vlan_a = 20
235
236
        for in_vlan_a in (10, None):
237
            for in_vlan_z in (3, None):
238
                with self.subTest(in_vlan_a=in_vlan_a, in_vlan_z=in_vlan_z):
239
                    # pylint: disable=protected-access
240
                    flow_mod = evc._prepare_push_flow(interface_a, interface_z,
241
                                                      in_vlan_a, out_vlan_a,
242
                                                      in_vlan_z)
243
                    expected_flow_mod = {
244
                        'match': {'in_port': interface_a.port_number},
245
                        'cookie': evc.get_cookie(),
246
                        'actions': [
247
                            {'action_type': 'push_vlan', 'tag_type': 's'},
248
                            {'action_type': 'set_vlan', 'vlan_id': out_vlan_a},
249
                            {
250
                                'action_type': 'output',
251
                                'port': interface_z.port_number
252
                            }
253
                        ],
254
                        "priority": EPL_SB_PRIORITY,
255
                    }
256
                    if in_vlan_a and in_vlan_z:
257
                        expected_flow_mod['match']['dl_vlan'] = in_vlan_a
258
                        expected_flow_mod['actions'].insert(0, {
259
                            'action_type': 'set_vlan', 'vlan_id': in_vlan_z
260
                        })
261
                        expected_flow_mod['priority'] = EVPL_SB_PRIORITY
262
                    elif in_vlan_a:
263
                        expected_flow_mod['match']['dl_vlan'] = in_vlan_a
264
                        expected_flow_mod['actions'].insert(0, {
265
                            'action_type': 'pop_vlan'
266
                        })
267
                        expected_flow_mod["priority"] = EVPL_SB_PRIORITY
268
                    elif in_vlan_z:
269
                        expected_flow_mod['actions'].insert(0, {
270
                            'action_type': 'set_vlan', 'vlan_id': in_vlan_z
271
                        })
272
                        expected_flow_mod['actions'].insert(0, {
273
                            'action_type': 'push_vlan', 'tag_type': 'c'
274
                        })
275
                        expected_flow_mod["priority"] = EPL_SB_PRIORITY
276
                    self.assertEqual(expected_flow_mod, flow_mod)
277
278
    @staticmethod
279
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
280
    def test_install_uni_flows(send_flow_mods_mock):
281
        """Test install uni flows method.
282
283
        This test will verify the flows send to the send_flow_mods method.
284
        """
285
        evc = TestEVC.create_evc_inter_switch()
286
287
        # pylint: disable=protected-access
288
        evc._install_uni_flows()
289
        send_flow_mods_mock.assert_not_called()
290
291
        # pylint: disable=protected-access
292
        evc._install_uni_flows(evc.primary_links)
293
294
        expected_flow_mod_a = [
295
            {
296
                "match": {
297
                    "in_port": evc.uni_a.interface.port_number,
298
                    "dl_vlan": evc.uni_a.user_tag.value,
299
                },
300
                "cookie": evc.get_cookie(),
301
                "actions": [
302
                    {
303
                        "action_type": "set_vlan",
304
                        "vlan_id": evc.uni_z.user_tag.value
305
                    },
306
                    {"action_type": "push_vlan", "tag_type": "s"},
307
                    {
308
                        "action_type": "set_vlan",
309
                        "vlan_id": evc.primary_links[0]
310
                        .get_metadata("s_vlan")
311
                        .value,
312
                    },
313
                    {
314
                        "action_type": "output",
315
                        "port": evc.primary_links[0].endpoint_a.port_number,
316
                    },
317
                ],
318
                "priority": EVPL_SB_PRIORITY,
319
            },
320
            {
321
                "match": {
322
                    "in_port": evc.primary_links[0].endpoint_a.port_number,
323
                    "dl_vlan": evc.primary_links[0]
324
                    .get_metadata("s_vlan")
325
                    .value,
326
                },
327
                "cookie": evc.get_cookie(),
328
                "actions": [
329
                    {"action_type": "pop_vlan"},
330
                    {
331
                        "action_type": "output",
332
                        "port": evc.uni_a.interface.port_number,
333
                    },
334
                ],
335
                "priority": EVPL_SB_PRIORITY,
336
            },
337
        ]
338
339
        send_flow_mods_mock.assert_any_call(
340
            evc.uni_a.interface.switch.id, expected_flow_mod_a
341
        )
342
343
        expected_flow_mod_z = [
344
            {
345
                "match": {
346
                    "in_port": evc.uni_z.interface.port_number,
347
                    "dl_vlan": evc.uni_z.user_tag.value,
348
                },
349
                "cookie": evc.get_cookie(),
350
                "actions": [
351
                    {
352
                        "action_type": "set_vlan",
353
                        "vlan_id": evc.uni_a.user_tag.value
354
                    },
355
                    {"action_type": "push_vlan", "tag_type": "s"},
356
                    {
357
                        "action_type": "set_vlan",
358
                        "vlan_id": evc.primary_links[-1]
359
                        .get_metadata("s_vlan")
360
                        .value,
361
                    },
362
                    {
363
                        "action_type": "output",
364
                        "port": evc.primary_links[-1].endpoint_b.port_number,
365
                    },
366
                ],
367
                "priority": EVPL_SB_PRIORITY,
368
            },
369
            {
370
                "match": {
371
                    "in_port": evc.primary_links[-1].endpoint_b.port_number,
372
                    "dl_vlan": evc.primary_links[-1]
373
                    .get_metadata("s_vlan")
374
                    .value,
375
                },
376
                "cookie": evc.get_cookie(),
377
                "actions": [
378
                    {"action_type": "pop_vlan"},
379
                    {
380
                        "action_type": "output",
381
                        "port": evc.uni_z.interface.port_number,
382
                    },
383
                ],
384
                "priority": EVPL_SB_PRIORITY,
385
            },
386
        ]
387
388
        send_flow_mods_mock.assert_any_call(
389
            evc.uni_z.interface.switch.id, expected_flow_mod_z
390
        )
391
392 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
393
    def create_evc_inter_switch():
394
        """Create inter-switch EVC with two links in the path"""
395
        uni_a = get_uni_mocked(
396
            interface_port=2,
397
            tag_value=82,
398
            switch_id=1,
399
            switch_dpid=1,
400
            is_valid=True,
401
        )
402
        uni_z = get_uni_mocked(
403
            interface_port=3,
404
            tag_value=83,
405
            switch_id=3,
406
            switch_dpid=3,
407
            is_valid=True,
408
        )
409
410
        attributes = {
411
            "controller": get_controller_mock(),
412
            "name": "custom_name",
413
            "id": "1",
414
            "uni_a": uni_a,
415
            "uni_z": uni_z,
416
            "primary_links": [
417
                get_link_mocked(
418
                    switch_a=Switch(1),
419
                    switch_b=Switch(2),
420
                    endpoint_a_port=9,
421
                    endpoint_b_port=10,
422
                    metadata={"s_vlan": 5},
423
                ),
424
                get_link_mocked(
425
                    switch_a=Switch(2),
426
                    switch_b=Switch(3),
427
                    endpoint_a_port=11,
428
                    endpoint_b_port=12,
429
                    metadata={"s_vlan": 6},
430
                ),
431
            ],
432
        }
433
        return EVC(**attributes)
434
435 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
436
    def create_evc_inter_switch_same_dpid():
437
        """Create inter-switch EVC with two links in the path"""
438
        uni_a = get_uni_mocked(
439
            interface_port=2,
440
            tag_value=82,
441
            switch_id=1,
442
            switch_dpid=1,
443
            is_valid=True,
444
        )
445
        uni_z = get_uni_mocked(
446
            interface_port=3,
447
            tag_value=83,
448
            switch_id=1,
449
            switch_dpid=1,
450
            is_valid=True,
451
        )
452
453
        attributes = {
454
            "controller": get_controller_mock(),
455
            "name": "custom_name",
456
            "id": "1",
457
            "uni_a": uni_a,
458
            "uni_z": uni_z,
459
            "primary_links": [
460
                get_link_mocked(
461
                    switch_a=Switch(1),
462
                    switch_b=Switch(2),
463
                    endpoint_a_port=9,
464
                    endpoint_b_port=10,
465
                    metadata={"s_vlan": 5},
466
                ),
467
                get_link_mocked(
468
                    switch_a=Switch(2),
469
                    switch_b=Switch(3),
470
                    endpoint_a_port=11,
471
                    endpoint_b_port=12,
472
                    metadata={"s_vlan": 6},
473
                ),
474
            ],
475
        }
476
        return EVC(**attributes)
477
478
    @staticmethod
479
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
480
    def test_install_nni_flows(send_flow_mods_mock):
481
        """Test install nni flows method.
482
483
        This test will verify the flows send to the send_flow_mods method.
484
        """
485
        evc = TestEVC.create_evc_inter_switch()
486
487
        # pylint: disable=protected-access
488
        evc._install_nni_flows(evc.primary_links)
489
490
        in_vlan = evc.primary_links[0].get_metadata("s_vlan").value
491
        out_vlan = evc.primary_links[-1].get_metadata("s_vlan").value
492
493
        in_port = evc.primary_links[0].endpoint_b.port_number
494
        out_port = evc.primary_links[-1].endpoint_a.port_number
495
496
        expected_flow_mods = [
497
            {
498
                "match": {"in_port": in_port, "dl_vlan": in_vlan},
499
                "cookie": evc.get_cookie(),
500
                "actions": [
501
                    {"action_type": "set_vlan", "vlan_id": out_vlan},
502
                    {"action_type": "output", "port": out_port},
503
                ],
504
                "priority": EVPL_SB_PRIORITY
505
            },
506
            {
507
                "match": {"in_port": out_port, "dl_vlan": out_vlan},
508
                "cookie": evc.get_cookie(),
509
                "actions": [
510
                    {"action_type": "set_vlan", "vlan_id": in_vlan},
511
                    {"action_type": "output", "port": in_port},
512
                ],
513
                "priority": EVPL_SB_PRIORITY
514
            },
515
        ]
516
517
        dpid = evc.primary_links[0].endpoint_b.switch.id
518
        send_flow_mods_mock.assert_called_once_with(dpid, expected_flow_mods)
519
520
    @patch("requests.post")
521
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
522
    @patch("napps.kytos.mef_eline.models.evc.log")
523
    @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans")
524
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows")
525
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows")
526
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_direct_uni_flows")
527
    @patch("napps.kytos.mef_eline.models.evc.EVC.activate")
528
    @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy")
529
    def test_deploy_successfully(self, *args):
530
        """Test if all methods to deploy are called."""
531
        # pylint: disable=too-many-locals
532
        (
533
            should_deploy_mock,
534
            activate_mock,
535
            install_direct_uni_flows_mock,
536
            install_uni_flows_mock,
537
            install_nni_flows,
538
            chose_vlans_mock,
539
            log_mock,
540
            _,
541
            requests_mock,
542
        ) = args
543
544
        response = MagicMock()
545
        response.status_code = 201
546
        requests_mock.return_value = response
547
548
        should_deploy_mock.return_value = True
549
        evc = self.create_evc_inter_switch()
550
        deployed = evc.deploy_to_path(evc.primary_links)
551
552
        self.assertEqual(should_deploy_mock.call_count, 1)
553
        self.assertEqual(activate_mock.call_count, 1)
554
        self.assertEqual(install_uni_flows_mock.call_count, 1)
555
        self.assertEqual(install_nni_flows.call_count, 1)
556
        self.assertEqual(chose_vlans_mock.call_count, 1)
557
        log_mock.info.assert_called_with(f"{evc} was deployed.")
558
        self.assertTrue(deployed)
559
560
        # intra switch EVC
561
        evc = self.create_evc_intra_switch()
562
        self.assertTrue(evc.deploy_to_path(evc.primary_links))
563
        self.assertEqual(install_direct_uni_flows_mock.call_count, 1)
564
        self.assertEqual(activate_mock.call_count, 2)
565
        self.assertEqual(log_mock.info.call_count, 2)
566
        log_mock.info.assert_called_with(f"{evc} was deployed.")
567
568
    @patch("requests.post")
569
    @patch("napps.kytos.mef_eline.models.evc.log")
570
    @patch("napps.kytos.mef_eline.models.evc.EVC.discover_new_paths")
571
    @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans")
572
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows")
573
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows")
574
    @patch("napps.kytos.mef_eline.models.evc.EVC.activate")
575
    @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy")
576
    @patch("napps.kytos.mef_eline.models.EVC.sync")
577
    def test_deploy_fail(self, *args):
578
        """Test if all methods is ignored when the should_deploy is false."""
579
        # pylint: disable=too-many-locals
580
        (
581
            sync_mock,
582
            should_deploy_mock,
583
            activate_mock,
584
            install_uni_flows_mock,
585
            install_nni_flows,
586
            choose_vlans_mock,
587
            discover_new_paths_mock,
588
            log_mock,
589
            requests_mock,
590
        ) = args
591
592
        response = MagicMock()
593
        response.status_code = 201
594
        requests_mock.return_value = response
595
596
        evc = self.create_evc_inter_switch()
597
        should_deploy_mock.return_value = False
598
        discover_new_paths_mock.return_value = []
599
        deployed = evc.deploy_to_path()
600
601
        self.assertEqual(discover_new_paths_mock.call_count, 1)
602
        self.assertEqual(should_deploy_mock.call_count, 1)
603
        self.assertEqual(activate_mock.call_count, 0)
604
        self.assertEqual(install_uni_flows_mock.call_count, 0)
605
        self.assertEqual(install_nni_flows.call_count, 0)
606
        self.assertEqual(choose_vlans_mock.call_count, 0)
607
        self.assertEqual(log_mock.info.call_count, 0)
608
        self.assertEqual(sync_mock.call_count, 1)
609
        self.assertFalse(deployed)
610
611
        # NoTagAvailable on static path
612
        should_deploy_mock.return_value = True
613
        choose_vlans_mock.side_effect = KytosNoTagAvailableError("error")
614
        self.assertFalse(evc.deploy_to_path(evc.primary_links))
615
616
        # NoTagAvailable on dynamic path
617
        should_deploy_mock.return_value = False
618
        discover_new_paths_mock.return_value = [Path(['a', 'b'])]
619
        choose_vlans_mock.side_effect = KytosNoTagAvailableError("error")
620
        self.assertFalse(evc.deploy_to_path(evc.primary_links))
621
622
    @patch("napps.kytos.mef_eline.models.evc.log")
623
    @patch(
624
        "napps.kytos.mef_eline.models.evc.EVC.discover_new_paths",
625
        return_value=[],
626
    )
627
    @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans")
628
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows")
629
    @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy")
630
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_current_flows")
631
    @patch("napps.kytos.mef_eline.models.evc.EVC.sync")
632
    def test_deploy_error(self, *args):
633
        """Test if all methods is ignored when the should_deploy is false."""
634
        # pylint: disable=too-many-locals
635
        (
636
            sync_mock,
637
            remove_current_flows,
638
            should_deploy_mock,
639
            install_nni_flows,
640
            choose_vlans_mock,
641
            discover_new_paths,
642
            log_mock,
643
        ) = args
644
645
        install_nni_flows.side_effect = FlowModException
646
        should_deploy_mock.return_value = True
647
        uni_a = get_uni_mocked(
648
            interface_port=2,
649
            tag_value=82,
650
            switch_id="switch_uni_a",
651
            is_valid=True,
652
        )
653
        uni_z = get_uni_mocked(
654
            interface_port=3,
655
            tag_value=83,
656
            switch_id="switch_uni_z",
657
            is_valid=True,
658
        )
659
660
        primary_links = [
661
            get_link_mocked(
662
                endpoint_a_port=9, endpoint_b_port=10, metadata={"s_vlan": 5}
663
            ),
664
            get_link_mocked(
665
                endpoint_a_port=11, endpoint_b_port=12, metadata={"s_vlan": 6}
666
            ),
667
        ]
668
669
        attributes = {
670
            "controller": get_controller_mock(),
671
            "name": "custom_name",
672
            "uni_a": uni_a,
673
            "uni_z": uni_z,
674
            "primary_links": primary_links,
675
            "queue_id": 5,
676
        }
677
        # Setup path to deploy
678
        path = Path()
679
        path.append(primary_links[0])
680
        path.append(primary_links[1])
681
682
        evc = EVC(**attributes)
683
684
        deployed = evc.deploy_to_path(path)
685
686
        self.assertEqual(discover_new_paths.call_count, 0)
687
        self.assertEqual(should_deploy_mock.call_count, 1)
688
        self.assertEqual(install_nni_flows.call_count, 1)
689
        self.assertEqual(choose_vlans_mock.call_count, 1)
690
        self.assertEqual(log_mock.error.call_count, 1)
691
        self.assertEqual(sync_mock.call_count, 0)
692
        self.assertEqual(remove_current_flows.call_count, 2)
693
        self.assertFalse(deployed)
694
695
    @patch("napps.kytos.mef_eline.models.evc.notify_link_available_tags")
696
    @patch("napps.kytos.mef_eline.models.evc.EVC.get_failover_path_candidates")
697
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows")
698
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows")
699
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_path_flows")
700
    @patch("napps.kytos.mef_eline.models.EVC.sync")
701
    def test_setup_failover_path(self, *args):
702
        """Test setup_failover_path method."""
703
        (
704
            sync_mock,
705
            remove_path_flows_mock,
706
            install_uni_flows_mock,
707
            install_nni_flows_mock,
708
            get_failover_path_candidates_mock,
709
            notify_mock,
710
        ) = args
711
712
        # case1: early return intra switch
713
        evc1 = self.create_evc_intra_switch()
714
715
        self.assertFalse(evc1.setup_failover_path())
716
        self.assertEqual(sync_mock.call_count, 0)
717
718
        # case2: early return not eligible for path failover
719
        evc2 = self.create_evc_inter_switch()
720
        evc2.is_eligible_for_failover_path = MagicMock(return_value=False)
721
722
        self.assertFalse(evc2.setup_failover_path())
723
        self.assertEqual(sync_mock.call_count, 0)
724
725
        # case3: success failover_path setup
726
        evc2.is_eligible_for_failover_path = MagicMock(return_value=True)
727
        evc2.failover_path = ["link1", "link2"]
728
        path_mock = MagicMock()
729
        path_mock.__iter__.return_value = ["link3"]
730
        get_failover_path_candidates_mock.return_value = [None, path_mock]
731
732
        self.assertTrue(evc2.setup_failover_path())
733
        remove_path_flows_mock.assert_called_with(["link1", "link2"])
734
        path_mock.choose_vlans.assert_called()
735
        notify_mock.assert_called()
736
        install_nni_flows_mock.assert_called_with(path_mock)
737
        install_uni_flows_mock.assert_called_with(path_mock, skip_in=True)
738
        self.assertEqual(evc2.failover_path, path_mock)
739
        self.assertEqual(sync_mock.call_count, 1)
740
741
        # case 4: failed to setup failover_path - No Tag available
742
        evc2.failover_path = []
743
        path_mock.choose_vlans.side_effect = KytosNoTagAvailableError("error")
744
        sync_mock.call_count = 0
745
746
        self.assertFalse(evc2.setup_failover_path())
747
        self.assertEqual(list(evc2.failover_path), [])
748
        self.assertEqual(sync_mock.call_count, 1)
749
750
        # case 5: failed to setup failover_path - FlowMod exception
751
        evc2.failover_path = []
752
        path_mock.choose_vlans.side_effect = None
753
        install_nni_flows_mock.side_effect = FlowModException("error")
754
        sync_mock.call_count = 0
755
756
        self.assertFalse(evc2.setup_failover_path())
757
        self.assertEqual(list(evc2.failover_path), [])
758
        self.assertEqual(sync_mock.call_count, 1)
759
        remove_path_flows_mock.assert_called_with(path_mock)
760
761
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy_to_path")
762
    @patch("napps.kytos.mef_eline.models.evc.EVC.discover_new_paths")
763
    def test_deploy_to_backup_path1(
764
        self, discover_new_paths_mocked, deploy_to_path_mocked
765
    ):
766
        """Test deployment when dynamic_backup_path is False in same switch"""
767
        uni_a = get_uni_mocked(interface_port=2, tag_value=82, is_valid=True)
768
        uni_z = get_uni_mocked(interface_port=3, tag_value=83, is_valid=True)
769
770
        switch = Mock(spec=Switch)
771
        uni_a.interface.switch = switch
772
        uni_z.interface.switch = switch
773
774
        attributes = {
775
            "controller": get_controller_mock(),
776
            "name": "custom_name",
777
            "uni_a": uni_a,
778
            "uni_z": uni_z,
779
            "enabled": True,
780
            "dynamic_backup_path": False,
781
        }
782
783
        evc = EVC(**attributes)
784
        discover_new_paths_mocked.return_value = []
785
        deploy_to_path_mocked.return_value = True
786
787
        deployed = evc.deploy_to_backup_path()
788
789
        deploy_to_path_mocked.assert_called_once_with()
790
        self.assertEqual(deployed, True)
791
792
    @patch("requests.post")
793
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
794
    @patch("napps.kytos.mef_eline.models.evc.log")
795
    @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans")
796
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows")
797
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows")
798
    @patch("napps.kytos.mef_eline.models.evc.EVC.activate")
799
    @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy")
800
    @patch("napps.kytos.mef_eline.models.evc.EVC.discover_new_paths")
801
    def test_deploy_without_path_case1(self, *args):
802
        """Test if not path is found a dynamic path is used."""
803
        # pylint: disable=too-many-locals
804
        (
805
            discover_new_paths_mocked,
806
            should_deploy_mock,
807
            activate_mock,
808
            install_uni_flows_mock,
809
            install_nni_flows,
810
            chose_vlans_mock,
811
            log_mock,
812
            _,
813
            requests_mock,
814
        ) = args
815
816
        response = MagicMock()
817
        response.status_code = 201
818
        requests_mock.return_value = response
819
820
        should_deploy_mock.return_value = False
821
        uni_a = get_uni_mocked(
822
            interface_port=2,
823
            tag_value=82,
824
            switch_id="switch_uni_a",
825
            is_valid=True,
826
        )
827
        uni_z = get_uni_mocked(
828
            interface_port=3,
829
            tag_value=83,
830
            switch_id="switch_uni_z",
831
            is_valid=True,
832
        )
833
834
        attributes = {
835
            "controller": get_controller_mock(),
836
            "name": "custom_name",
837
            "uni_a": uni_a,
838
            "uni_z": uni_z,
839
            "enabled": True,
840
            "dynamic_backup_path": False,
841
        }
842
843
        dynamic_backup_path = Path(
844
            [
845
                get_link_mocked(
846
                    endpoint_a_port=9,
847
                    endpoint_b_port=10,
848
                    metadata={"s_vlan": 5},
849
                ),
850
                get_link_mocked(
851
                    endpoint_a_port=11,
852
                    endpoint_b_port=12,
853
                    metadata={"s_vlan": 6},
854
                ),
855
            ]
856
        )
857
858
        evc = EVC(**attributes)
859
        discover_new_paths_mocked.return_value = [dynamic_backup_path]
860
861
        deployed = evc.deploy_to_path()
862
863
        self.assertEqual(should_deploy_mock.call_count, 1)
864
        self.assertEqual(discover_new_paths_mocked.call_count, 1)
865
        self.assertEqual(activate_mock.call_count, 1)
866
        self.assertEqual(install_uni_flows_mock.call_count, 1)
867
        self.assertEqual(install_nni_flows.call_count, 1)
868
        self.assertEqual(chose_vlans_mock.call_count, 1)
869
        log_mock.info.assert_called_with(f"{evc} was deployed.")
870
        self.assertTrue(deployed)
871
872
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.deploy_to_primary_path")
873
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.deploy_to_backup_path")
874
    @patch("napps.kytos.mef_eline.models.evc.emit_event")
875
    def test_deploy(self, *args):
876
        """Test method deploy"""
877
        (emit_event_mock, deploy_primary_mock, deploy_backup_mock) = args
878
879
        # case 1: deploy to primary
880
        self.evc_deploy.archived = False
881
        deploy_primary_mock.return_value = True
882
        self.assertTrue(self.evc_deploy.deploy())
883
        self.assertEqual(emit_event_mock.call_count, 1)
884
885
        # case 2: deploy to backup
886
        deploy_primary_mock.return_value = False
887
        deploy_backup_mock.return_value = True
888
        self.assertTrue(self.evc_deploy.deploy())
889
        self.assertEqual(emit_event_mock.call_count, 2)
890
891
        # case 3: fail to deploy to primary and backup
892
        deploy_backup_mock.return_value = False
893
        self.assertFalse(self.evc_deploy.deploy())
894
        self.assertEqual(emit_event_mock.call_count, 2)
895
896
        # case 4: archived
897
        self.evc_deploy.archived = True
898
        self.assertFalse(self.evc_deploy.deploy())
899
        self.assertEqual(emit_event_mock.call_count, 2)
900
901
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.remove_current_flows")
902
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.sync")
903
    @patch("napps.kytos.mef_eline.models.evc.emit_event")
904
    def test_remove(self, *args):
905
        """Test method remove"""
906
        (emit_event_mock, sync_mock, remove_flows_mock) = args
907
        self.evc_deploy.remove()
908
        remove_flows_mock.assert_called()
909
        sync_mock.assert_called()
910
        emit_event_mock.assert_called()
911
        self.assertFalse(self.evc_deploy.is_enabled())
912
913
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
914
    @patch("napps.kytos.mef_eline.models.evc.notify_link_available_tags")
915
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
916
    @patch("napps.kytos.mef_eline.models.evc.log.error")
917
    def test_remove_current_flows(self, *args):
918
        """Test remove current flows."""
919
        # pylint: disable=too-many-locals
920
        (log_error_mock, send_flow_mods_mocked, notify_mock, _) = args
921
        uni_a = get_uni_mocked(
922
            interface_port=2,
923
            tag_value=82,
924
            switch_id="switch_uni_a",
925
            is_valid=True,
926
        )
927
        uni_z = get_uni_mocked(
928
            interface_port=3,
929
            tag_value=83,
930
            switch_id="switch_uni_z",
931
            is_valid=True,
932
        )
933
934
        switch_a = Switch("00:00:00:00:00:01")
935
        switch_b = Switch("00:00:00:00:00:02")
936
        switch_c = Switch("00:00:00:00:00:03")
937
938
        attributes = {
939
            "controller": get_controller_mock(),
940
            "name": "custom_name",
941
            "uni_a": uni_a,
942
            "uni_z": uni_z,
943
            "active": True,
944
            "enabled": True,
945
            "primary_links": [
946
                get_link_mocked(
947
                    switch_a=switch_a,
948
                    switch_b=switch_b,
949
                    endpoint_a_port=9,
950
                    endpoint_b_port=10,
951
                    metadata={"s_vlan": 5},
952
                ),
953
                get_link_mocked(
954
                    switch_a=switch_b,
955
                    switch_b=switch_c,
956
                    endpoint_a_port=11,
957
                    endpoint_b_port=12,
958
                    metadata={"s_vlan": 6},
959
                ),
960
            ],
961
        }
962
963
        evc = EVC(**attributes)
964
965
        evc.current_path = evc.primary_links
966
        evc.remove_current_flows()
967
        notify_mock.assert_called()
968
969
        self.assertEqual(send_flow_mods_mocked.call_count, 5)
970
        self.assertFalse(evc.is_active())
971
        flows = [
972
            {"cookie": evc.get_cookie(), "cookie_mask": 18446744073709551615}
973
        ]
974
        switch_1 = evc.primary_links[0].endpoint_a.switch
975
        switch_2 = evc.primary_links[0].endpoint_b.switch
976
        send_flow_mods_mocked.assert_any_call(switch_1.id, flows, 'delete',
977
                                              force=True)
978
        send_flow_mods_mocked.assert_any_call(switch_2.id, flows, 'delete',
979
                                              force=True)
980
981
        send_flow_mods_mocked.side_effect = FlowModException("error")
982
        evc.remove_current_flows()
983
        log_error_mock.assert_called()
984
985
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
986
    @patch("napps.kytos.mef_eline.models.evc.notify_link_available_tags")
987
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
988
    @patch("napps.kytos.mef_eline.models.evc.log.error")
989
    def test_remove_failover_flows_exclude_uni_switches(self, *args):
990
        """Test remove failover flows excluding UNI switches."""
991
        # pylint: disable=too-many-locals
992
        (log_error_mock, send_flow_mods_mocked,
993
         notify_mock, mock_upsert) = args
994
        uni_a = get_uni_mocked(
995
            interface_port=2,
996
            tag_value=82,
997
            switch_id="00:00:00:00:00:00:00:01",
998
            is_valid=True,
999
        )
1000
        uni_z = get_uni_mocked(
1001
            interface_port=3,
1002
            tag_value=83,
1003
            switch_id="00:00:00:00:00:00:00:03",
1004
            is_valid=True,
1005
        )
1006
1007
        switch_a = Switch("00:00:00:00:00:00:00:01")
1008
        switch_b = Switch("00:00:00:00:00:00:00:02")
1009
        switch_c = Switch("00:00:00:00:00:00:00:03")
1010
1011
        attributes = {
1012
            "controller": get_controller_mock(),
1013
            "name": "custom_name",
1014
            "uni_a": uni_a,
1015
            "uni_z": uni_z,
1016
            "active": True,
1017
            "enabled": True,
1018
            "failover_path": [
1019
                get_link_mocked(
1020
                    switch_a=switch_a,
1021
                    switch_b=switch_b,
1022
                    endpoint_a_port=9,
1023
                    endpoint_b_port=10,
1024
                    metadata={"s_vlan": 5},
1025
                ),
1026
                get_link_mocked(
1027
                    switch_a=switch_b,
1028
                    switch_b=switch_c,
1029
                    endpoint_a_port=11,
1030
                    endpoint_b_port=12,
1031
                    metadata={"s_vlan": 6},
1032
                ),
1033
            ],
1034
        }
1035
1036
        evc = EVC(**attributes)
1037
        evc.remove_failover_flows(exclude_uni_switches=True, sync=True)
1038
        notify_mock.assert_called()
1039
1040
        assert send_flow_mods_mocked.call_count == 1
1041
        flows = [
1042
            {"cookie": evc.get_cookie(),
1043
             "cookie_mask": int(0xffffffffffffffff)}
1044
        ]
1045
        send_flow_mods_mocked.assert_any_call(switch_b.id, flows, 'delete',
1046
                                              force=True)
1047
        assert mock_upsert.call_count == 1
1048
1049
        send_flow_mods_mocked.side_effect = FlowModException("error")
1050
        evc.remove_current_flows()
1051
        log_error_mock.assert_called()
1052
1053
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1054
    @patch("napps.kytos.mef_eline.models.evc.notify_link_available_tags")
1055
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
1056
    def test_remove_failover_flows_include_all(self, *args):
1057
        """Test remove failover flows including UNI switches."""
1058
        # pylint: disable=too-many-locals
1059
        (send_flow_mods_mocked,
1060
         notify_mock, mock_upsert) = args
1061
        uni_a = get_uni_mocked(
1062
            interface_port=2,
1063
            tag_value=82,
1064
            switch_id="00:00:00:00:00:00:00:01",
1065
            is_valid=True,
1066
        )
1067
        uni_z = get_uni_mocked(
1068
            interface_port=3,
1069
            tag_value=83,
1070
            switch_id="00:00:00:00:00:00:00:03",
1071
            is_valid=True,
1072
        )
1073
1074
        switch_a = Switch("00:00:00:00:00:00:00:01")
1075
        switch_b = Switch("00:00:00:00:00:00:00:02")
1076
        switch_c = Switch("00:00:00:00:00:00:00:03")
1077
1078
        attributes = {
1079
            "controller": get_controller_mock(),
1080
            "name": "custom_name",
1081
            "uni_a": uni_a,
1082
            "uni_z": uni_z,
1083
            "active": True,
1084
            "enabled": True,
1085
            "failover_path": [
1086
                get_link_mocked(
1087
                    switch_a=switch_a,
1088
                    switch_b=switch_b,
1089
                    endpoint_a_port=9,
1090
                    endpoint_b_port=10,
1091
                    metadata={"s_vlan": 5},
1092
                ),
1093
                get_link_mocked(
1094
                    switch_a=switch_b,
1095
                    switch_b=switch_c,
1096
                    endpoint_a_port=11,
1097
                    endpoint_b_port=12,
1098
                    metadata={"s_vlan": 6},
1099
                ),
1100
            ],
1101
        }
1102
1103
        evc = EVC(**attributes)
1104
        evc.remove_failover_flows(exclude_uni_switches=False, sync=True)
1105
        notify_mock.assert_called()
1106
1107
        assert send_flow_mods_mocked.call_count == 3
1108
        flows = [
1109
            {"cookie": evc.get_cookie(),
1110
             "cookie_mask": int(0xffffffffffffffff)}
1111
        ]
1112
        send_flow_mods_mocked.assert_any_call(switch_a.id, flows, 'delete',
1113
                                              force=True)
1114
        send_flow_mods_mocked.assert_any_call(switch_b.id, flows, 'delete',
1115
                                              force=True)
1116
        send_flow_mods_mocked.assert_any_call(switch_c.id, flows, 'delete',
1117
                                              force=True)
1118
        assert mock_upsert.call_count == 1
1119
1120
    @staticmethod
1121
    def create_evc_intra_switch():
1122
        """Create intra-switch EVC."""
1123
        switch = Mock(spec=Switch)
1124
        switch.dpid = 2
1125
        switch.id = switch.dpid
1126
        interface_a = Interface("eth0", 1, switch)
1127
        interface_z = Interface("eth1", 3, switch)
1128
        uni_a = get_uni_mocked(
1129
            tag_value=82,
1130
            is_valid=True,
1131
        )
1132
        uni_z = get_uni_mocked(
1133
            tag_value=84,
1134
            is_valid=True,
1135
        )
1136
        uni_a.interface = interface_a
1137
        uni_z.interface = interface_z
1138
        attributes = {
1139
            "controller": get_controller_mock(),
1140
            "name": "custom_name",
1141
            "id": "1",
1142
            "uni_a": uni_a,
1143
            "uni_z": uni_z,
1144
            "enabled": True,
1145
        }
1146
        return EVC(**attributes)
1147
1148
    @staticmethod
1149
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
1150
    def test_deploy_direct_uni_flows(send_flow_mods_mock):
1151
        """Test _install_direct_uni_flows."""
1152
        evc = TestEVC.create_evc_intra_switch()
1153
1154
        # Test 1: both UNIs with TAG
1155
        expected_dpid = evc.uni_a.interface.switch.id
1156
        expected_flows = [
1157
            {
1158
                "match": {"in_port": 1, "dl_vlan": 82},
1159
                "cookie": evc.get_cookie(),
1160
                "actions": [
1161
                    {"action_type": "set_vlan", "vlan_id": 84},
1162
                    {"action_type": "output", "port": 3},
1163
                ],
1164
                "priority": EVPL_SB_PRIORITY
1165
            },
1166
            {
1167
                "match": {"in_port": 3, "dl_vlan": 84},
1168
                "cookie": evc.get_cookie(),
1169
                "actions": [
1170
                    {"action_type": "set_vlan", "vlan_id": 82},
1171
                    {"action_type": "output", "port": 1},
1172
                ],
1173
                "priority": EVPL_SB_PRIORITY
1174
            }
1175
        ]
1176
1177
        # pylint: disable=protected-access
1178
        evc._install_direct_uni_flows()
1179
        send_flow_mods_mock.assert_called_once_with(
1180
            expected_dpid, expected_flows
1181
        )
1182
1183
        # Test2: no TAG in UNI_A
1184
        uni_a_tag = evc.uni_a.user_tag
1185
        evc.uni_a.user_tag = None
1186
        expected_flows_no_tag_a = [
1187
            {
1188
                "match": {"in_port": 1},
1189
                "cookie": evc.get_cookie(),
1190
                "actions": [
1191
                    {"action_type": "set_vlan", "vlan_id": 84},
1192
                    {"action_type": "output", "port": 3},
1193
                ],
1194
                "priority": EPL_SB_PRIORITY
1195
            },
1196
            {
1197
                "match": {"in_port": 3, "dl_vlan": 84},
1198
                "cookie": evc.get_cookie(),
1199
                "actions": [
1200
                    {"action_type": "pop_vlan"},
1201
                    {"action_type": "output", "port": 1},
1202
                ],
1203
                "priority": EVPL_SB_PRIORITY
1204
            }
1205
        ]
1206
        evc._install_direct_uni_flows()
1207
        send_flow_mods_mock.assert_called_with(
1208
            expected_dpid, expected_flows_no_tag_a
1209
        )
1210
        evc.uni_a.user_tag = uni_a_tag
1211
1212
        # Test3: no TAG in UNI_Z
1213
        uni_z_tag = evc.uni_z.user_tag
1214
        evc.uni_z.user_tag = None
1215
        expected_flows_no_tag_z = [
1216
            {
1217
                "match": {"in_port": 1, "dl_vlan": 82},
1218
                "cookie": evc.get_cookie(),
1219
                "actions": [
1220
                    {"action_type": "pop_vlan"},
1221
                    {"action_type": "output", "port": 3},
1222
                ],
1223
                "priority": EVPL_SB_PRIORITY
1224
            },
1225
            {
1226
                "match": {"in_port": 3},
1227
                "cookie": evc.get_cookie(),
1228
                "actions": [
1229
                    {"action_type": "set_vlan", "vlan_id": 82},
1230
                    {"action_type": "output", "port": 1},
1231
                ],
1232
                "priority": EPL_SB_PRIORITY
1233
            }
1234
        ]
1235
        evc._install_direct_uni_flows()
1236
        send_flow_mods_mock.assert_called_with(
1237
            expected_dpid, expected_flows_no_tag_z
1238
        )
1239
        evc.uni_z.user_tag = uni_z_tag
1240
1241
        # Test3: no TAG in both UNI_Z and UNI_Z
1242
        evc.uni_a.user_tag = None
1243
        evc.uni_z.user_tag = None
1244
        expected_flows_no_tag = [
1245
            {
1246
                "match": {"in_port": 1},
1247
                "cookie": evc.get_cookie(),
1248
                "actions": [{"action_type": "output", "port": 3}],
1249
                "priority": EPL_SB_PRIORITY
1250
            },
1251
            {
1252
                "match": {"in_port": 3},
1253
                "cookie": evc.get_cookie(),
1254
                "actions": [{"action_type": "output", "port": 1}],
1255
                "priority": EPL_SB_PRIORITY
1256
            }
1257
        ]
1258
        evc._install_direct_uni_flows()
1259
        send_flow_mods_mock.assert_called_with(
1260
            expected_dpid, expected_flows_no_tag
1261
        )
1262
#
1263
#        print(evc._prepare_direct_uni_flows())
1264
#        evc.uni_a.user_tag = uni_a_tag
1265
#        uni_z_tag = evc.uni_z.user_tag
1266
#        evc.uni_z.user_tag = None
1267
#        print(evc._prepare_direct_uni_flows())
1268
#        evc.uni_z.user_tag = uni_z_tag
1269
#        evc.uni_a.user_tag = None
1270
#        evc.uni_z.user_tag = None
1271
#        print(evc._prepare_direct_uni_flows())
1272
#        self.assertTrue(False)
1273
1274
    def test_is_affected_by_link(self):
1275
        """Test is_affected_by_link method"""
1276
        self.evc_deploy.current_path = Path(['a', 'b', 'c'])
1277
        self.assertTrue(self.evc_deploy.is_affected_by_link('b'))
1278
1279
    def test_is_backup_path_affected_by_link(self):
1280
        """Test is_backup_path_affected_by_link method"""
1281
        self.evc_deploy.backup_path = Path(['a', 'b', 'c'])
1282
        self.assertFalse(self.evc_deploy.is_backup_path_affected_by_link('d'))
1283
1284
    def test_is_primary_path_affected_by_link(self):
1285
        """Test is_primary_path_affected_by_link method"""
1286
        self.evc_deploy.primary_path = Path(['a', 'b', 'c'])
1287
        self.assertTrue(self.evc_deploy.is_primary_path_affected_by_link('c'))
1288
1289
    def test_is_using_primary_path(self):
1290
        """Test is_using_primary_path method"""
1291
        self.evc_deploy.primary_path = Path(['a', 'b', 'c'])
1292
        self.evc_deploy.current_path = Path(['e', 'f', 'g'])
1293
        self.assertFalse(self.evc_deploy.is_using_primary_path())
1294
1295
    def test_is_using_backup_path(self):
1296
        """Test is_using_backup_path method"""
1297
        self.evc_deploy.backup_path = Path(['a', 'b', 'c'])
1298
        self.evc_deploy.current_path = Path(['e', 'f', 'g'])
1299
        self.assertFalse(self.evc_deploy.is_using_backup_path())
1300
1301
    @patch('napps.kytos.mef_eline.models.path.Path.status')
1302
    def test_is_using_dynamic_path(self, mock_status):
1303
        """Test is_using_dynamic_path method"""
1304
        mock_status.return_value = False
1305
        self.evc_deploy.backup_path = Path([])
1306
        self.evc_deploy.primary_path = Path([])
1307
        self.assertFalse(self.evc_deploy.is_using_dynamic_path())
1308
1309
    def test_get_path_status(self):
1310
        """Test get_path_status method"""
1311
        path = Path([])
1312
        self.assertEqual(
1313
            self.evc_deploy.get_path_status(path),
1314
            EntityStatus.DISABLED
1315
        )
1316
        path = Path([
1317
            get_link_mocked(status=EntityStatus.UP),
1318
            get_link_mocked(status=EntityStatus.DOWN)
1319
        ])
1320
        self.assertEqual(
1321
            self.evc_deploy.get_path_status(path),
1322
            EntityStatus.DOWN
1323
        )
1324
        path = Path([
1325
            get_link_mocked(status=EntityStatus.UP),
1326
            get_link_mocked(status=EntityStatus.UP)
1327
        ])
1328
        self.assertEqual(
1329
            self.evc_deploy.get_path_status(path),
1330
            EntityStatus.UP
1331
        )
1332
1333
    @patch("napps.kytos.mef_eline.models.evc.EVC._prepare_uni_flows")
1334
    def test_get_failover_flows(self, prepare_uni_flows_mock):
1335
        """Test get_failover_flows method."""
1336
        evc = self.create_evc_inter_switch()
1337
        evc.failover_path = Path([])
1338
        self.assertEqual(evc.get_failover_flows(), {})
1339
1340
        path = MagicMock()
1341
        evc.failover_path = path
1342
        evc.get_failover_flows()
1343
        prepare_uni_flows_mock.assert_called_with(path, skip_out=True)
1344
1345
    @patch("napps.kytos.mef_eline.models.evc.log")
1346
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
1347
    @patch("napps.kytos.mef_eline.models.path.Path.make_vlans_available")
1348
    def test_remove_path_flows(self, *args):
1349
        """Test remove path flows."""
1350
        (
1351
            make_vlans_available_mock,
1352
            send_flow_mods_mock,
1353
            log_mock,
1354
        ) = args
1355
1356
        evc = self.create_evc_inter_switch()
1357
1358
        evc.remove_path_flows()
1359
        make_vlans_available_mock.assert_not_called()
1360
1361
        expected_flows_1 = [
1362
            {
1363
                'cookie': 12249790986447749121,
1364
                'cookie_mask': 18446744073709551615,
1365
                'match': {'in_port': 9, 'dl_vlan':  5}
1366
            },
1367
        ]
1368
        expected_flows_2 = [
1369
            {
1370
                'cookie': 12249790986447749121,
1371
                'cookie_mask': 18446744073709551615,
1372
                'match': {'in_port': 10, 'dl_vlan': 5}
1373
            },
1374
            {
1375
                'cookie': 12249790986447749121,
1376
                'cookie_mask': 18446744073709551615,
1377
                'match': {'in_port': 11, 'dl_vlan': 6}
1378
            },
1379
        ]
1380
        expected_flows_3 = [
1381
            {
1382
                'cookie': 12249790986447749121,
1383
                'cookie_mask': 18446744073709551615,
1384
                'match': {'in_port': 12, 'dl_vlan': 6}
1385
            },
1386
        ]
1387
1388
        evc.remove_path_flows(evc.primary_links)
1389
        send_flow_mods_mock.assert_has_calls([
1390
            call(1, expected_flows_1, 'delete', force=True),
1391
            call(2, expected_flows_2, 'delete', force=True),
1392
            call(3, expected_flows_3, 'delete', force=True),
1393
        ], any_order=True)
1394
1395
        send_flow_mods_mock.side_effect = FlowModException("err")
1396
        evc.remove_path_flows(evc.primary_links)
1397
        log_mock.error.assert_called()
1398
1399
    @patch("requests.put")
1400
    def test_run_sdntrace(self, put_mock):
1401
        """Test run_sdntrace method."""
1402
        evc = self.create_evc_inter_switch()
1403
        response = MagicMock()
1404
        response.status_code = 200
1405
        response.json.return_value = {"result": "ok"}
1406
        put_mock.return_value = response
1407
1408
        expected_endpoint = f"{SDN_TRACE_CP_URL}/trace"
1409
        expected_payload = {
1410
            'trace': {
1411
                'switch': {'dpid': 1, 'in_port': 2},
1412
                'eth': {'dl_type': 0x8100, 'dl_vlan': 82}
1413
            }
1414
        }
1415
1416
        result = evc.run_sdntrace(evc.uni_a)
1417
        put_mock.assert_called_with(expected_endpoint, json=expected_payload)
1418
        self.assertEqual(result, "ok")
1419
1420
        response.status_code = 400
1421
        result = evc.run_sdntrace(evc.uni_a)
1422
        self.assertEqual(result, [])
1423
1424
    @patch("requests.put")
1425
    def test_run_bulk_sdntraces(self, put_mock):
1426
        """Test run_bulk_sdntraces method for bulh request."""
1427
        evc = self.create_evc_inter_switch()
1428
        response = MagicMock()
1429
        response.status_code = 200
1430
        response.json.return_value = {"result": "ok"}
1431
        put_mock.return_value = response
1432
1433
        expected_endpoint = f"{SDN_TRACE_CP_URL}/traces"
1434
        expected_payload = [
1435
                            {
1436
                                'trace': {
1437
                                    'switch': {'dpid': 1, 'in_port': 2},
1438
                                    'eth': {'dl_type': 0x8100, 'dl_vlan': 82}
1439
                                }
1440
                            }
1441
                        ]
1442
        result = EVCDeploy.run_bulk_sdntraces([evc.uni_a])
1443
        put_mock.assert_called_with(
1444
                                    expected_endpoint,
1445
                                    json=expected_payload,
1446
                                    timeout=30
1447
                                )
1448
        self.assertEqual(result['result'], "ok")
1449
1450
        response.status_code = 400
1451
        result = EVCDeploy.run_bulk_sdntraces([evc.uni_a])
1452
        self.assertEqual(result, [])
1453
1454
    @patch("napps.kytos.mef_eline.models.evc.log")
1455
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.run_bulk_sdntraces")
1456
    def test_check_list_traces(self, run_bulk_sdntraces_mock, _):
1457
        """Test check_list_traces method."""
1458
        evc = self.create_evc_inter_switch()
1459
1460
        for link in evc.primary_links:
1461
            link.metadata['s_vlan'] = MagicMock(value=link.metadata['s_vlan'])
1462
        evc.current_path = evc.primary_links
1463
1464
        trace_a = [
1465
            {"dpid": 1, "port": 2, "time": "t1", "type": "start", "vlan": 82},
1466
            {"dpid": 2, "port": 10, "time": "t2", "type": "trace", "vlan": 5},
1467
            {"dpid": 3, "port": 12, "time": "t3", "type": "trace", "vlan": 6},
1468
        ]
1469
        trace_z = [
1470
            {"dpid": 3, "port": 3, "time": "t1", "type": "start", "vlan": 83},
1471
            {"dpid": 2, "port": 11, "time": "t2", "type": "trace", "vlan": 6},
1472
            {"dpid": 1, "port": 9, "time": "t3", "type": "trace", "vlan": 5},
1473
        ]
1474
1475
        run_bulk_sdntraces_mock.return_value = {
1476
                                                1: [trace_a],
1477
                                                3: [trace_z]
1478
                                            }
1479
        result = EVCDeploy.check_list_traces({evc.id: evc})
1480
        self.assertTrue(result[evc.id])
1481
1482
        # case2: fail incomplete trace from uni_a
1483
        run_bulk_sdntraces_mock.return_value = {
1484
                                                1: [trace_a[:2]],
1485
                                                3: [trace_z]
1486
        }
1487
        result = EVCDeploy.check_list_traces({evc.id: evc})
1488
        self.assertFalse(result[evc.id])
1489
1490
        # case3: fail incomplete trace from uni_z
1491
        run_bulk_sdntraces_mock.return_values = {
1492
                                                1: [trace_a],
1493
                                                3: [trace_z[:2]]
1494
        }
1495
        result = EVCDeploy.check_list_traces({evc.id: evc})
1496
        self.assertFalse(result[evc.id])
1497
1498
        # case4: fail wrong vlan id in trace from uni_a
1499
        trace_a[1]["vlan"] = 5
1500
        trace_z[1]["vlan"] = 99
1501
        run_bulk_sdntraces_mock.return_values = {
1502
                                                1: [trace_a],
1503
                                                3: [trace_z]
1504
        }
1505
        result = EVCDeploy.check_list_traces({evc.id: evc})
1506
        self.assertFalse(result[evc.id])
1507
1508
        # case5: fail wrong vlan id in trace from uni_z
1509
        trace_a[1]["vlan"] = 99
1510
        run_bulk_sdntraces_mock.return_values = {
1511
                                                1: [trace_a],
1512
                                                3: [trace_z]
1513
        }
1514
        result = EVCDeploy.check_list_traces({evc.id: evc})
1515
        self.assertFalse(result[evc.id])
1516
1517 View Code Duplication
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.run_bulk_sdntraces")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1518
    def test_check_list_traces_same_switch_unis(self, run_bulk_sdntraces_mock):
1519
        """Test check_list_traces method."""
1520
        evc = self.create_evc_inter_switch_same_dpid()
1521
1522
        for link in evc.primary_links:
1523
            link.metadata['s_vlan'] = MagicMock(value=link.metadata['s_vlan'])
1524
        evc.current_path = evc.primary_links
1525
1526
        trace_a = [
1527
            {"dpid": 1, "port": 2, "time": "t1", "type": "start", "vlan": 82},
1528
            {"dpid": 2, "port": 10, "time": "t2", "type": "trace", "vlan": 5},
1529
            {"dpid": 3, "port": 12, "time": "t3", "type": "trace", "vlan": 6},
1530
        ]
1531
        trace_z = [
1532
            {"dpid": 1, "port": 3, "time": "t1", "type": "start", "vlan": 83},
1533
            {"dpid": 2, "port": 11, "time": "t2", "type": "trace", "vlan": 6},
1534
            {"dpid": 1, "port": 9, "time": "t3", "type": "trace", "vlan": 5},
1535
        ]
1536
1537
        run_bulk_sdntraces_mock.return_value = {
1538
                                                1: [trace_a, trace_z]
1539
                                            }
1540
        result = EVCDeploy.check_list_traces({evc.id: evc})
1541
        self.assertTrue(result[evc.id])
1542
1543 View Code Duplication
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.run_bulk_sdntraces")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1544
    def test_check_list_traces_current_path_empty(self, bulk_sdntraces_mock):
1545
        """Test check_list_traces method."""
1546
        evc = self.create_evc_inter_switch_same_dpid()
1547
        for link in evc.primary_links:
1548
            link.metadata['s_vlan'] = MagicMock(value=link.metadata['s_vlan'])
1549
        evc.current_path = []
1550
1551
        trace_a = [
1552
            {"dpid": 1, "port": 2, "time": "t1", "type": "start", "vlan": 82},
1553
            {"dpid": 2, "port": 10, "time": "t2", "type": "trace", "vlan": 5},
1554
            {"dpid": 3, "port": 12, "time": "t3", "type": "trace", "vlan": 6},
1555
        ]
1556
        trace_z = [
1557
            {"dpid": 1, "port": 3, "time": "t1", "type": "start", "vlan": 83},
1558
            {"dpid": 2, "port": 11, "time": "t2", "type": "trace", "vlan": 6},
1559
            {"dpid": 1, "port": 9, "time": "t3", "type": "trace", "vlan": 5},
1560
        ]
1561
1562
        bulk_sdntraces_mock.return_value = {
1563
                                                1: [trace_a, trace_z]
1564
                                            }
1565
        result = EVCDeploy.check_list_traces({evc.id: evc})
1566
        self.assertEqual(len(result), 0)
1567
1568
    @patch(
1569
        "napps.kytos.mef_eline.models.path.DynamicPathManager"
1570
        ".get_disjoint_paths"
1571
    )
1572
    def test_get_failover_path_vandidates(self, get_disjoint_paths_mock):
1573
        """Test get_failover_path_candidates method"""
1574
        self.evc_deploy.get_failover_path_candidates()
1575
        get_disjoint_paths_mock.assert_called_once()
1576
1577
    def test_is_failover_path_affected_by_link(self):
1578
        """Test is_failover_path_affected_by_link method"""
1579
        link1 = get_link_mocked(endpoint_a_port=1, endpoint_b_port=2)
1580
        link2 = get_link_mocked(endpoint_a_port=3, endpoint_b_port=4)
1581
        link3 = get_link_mocked(endpoint_a_port=5, endpoint_b_port=6)
1582
        self.evc_deploy.failover_path = Path([link1, link2])
1583
        self.assertTrue(
1584
            self.evc_deploy.is_failover_path_affected_by_link(link1)
1585
        )
1586
        self.assertFalse(
1587
            self.evc_deploy.is_failover_path_affected_by_link(link3)
1588
        )
1589
1590
    def test_is_eligible_for_failover_path(self):
1591
        """Test is_eligible_for_failover_path method"""
1592
        self.assertFalse(self.evc_deploy.is_eligible_for_failover_path())
1593
        self.evc_deploy.dynamic_backup_path = True
1594
        self.evc_deploy.primary_path = Path([])
1595
        self.evc_deploy.backup_path = Path([])
1596
        self.assertTrue(self.evc_deploy.is_eligible_for_failover_path())
1597