Test Failed
Pull Request — master (#214)
by
unknown
07:09
created

TestEVC.test_install_uni_flows()   B

Complexity

Conditions 1

Size

Total Lines 112
Code Lines 65

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 65
dl 0
loc 112
rs 8.1454
c 0
b 0
f 0
cc 1
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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