Passed
Push — master ( e6735a...b235ee )
by Italo Valcy
02:28 queued 14s
created

TestEVC.create_evc_inter_switch()   A

Complexity

Conditions 1

Size

Total Lines 42
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

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