Test Failed
Pull Request — master (#407)
by Vinicius
15:31 queued 13:18
created

TestEVC.test_prepare_uni_flows()   B

Complexity

Conditions 3

Size

Total Lines 41
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 37
nop 4
dl 0
loc 41
ccs 0
cts 0
cp 0
crap 12
rs 8.9919
c 0
b 0
f 0
1
"""Method to thest EVCDeploy class."""
2 1
import sys
3 1
from unittest.mock import MagicMock, Mock, call, patch
4 1
import operator
5 1
import pytest
6 1
from kytos.lib.helpers import get_controller_mock
7
8 1
from kytos.core.common import EntityStatus
9 1
from kytos.core.exceptions import KytosNoTagAvailableError
10 1
from kytos.core.interface import Interface
11 1
from kytos.core.switch import Switch
12
from requests.exceptions import Timeout
13
# pylint: disable=wrong-import-position
14 1
sys.path.insert(0, "/var/lib/kytos/napps/..")
15
# pylint: enable=wrong-import-position
16
17 1
from napps.kytos.mef_eline.exceptions import FlowModException  # NOQA
18 1
from napps.kytos.mef_eline.models import EVC, EVCDeploy, Path  # NOQA
19 1
from napps.kytos.mef_eline.settings import (ANY_SB_PRIORITY,  # NOQA
20
                                            EPL_SB_PRIORITY, EVPL_SB_PRIORITY,
21
                                            MANAGER_URL,
22
                                            SDN_TRACE_CP_URL,
23 1
                                            UNTAGGED_SB_PRIORITY)
24
from napps.kytos.mef_eline.tests.helpers import (get_link_mocked,  # NOQA
25
                                                 get_uni_mocked)
26
27
28 1
# pylint: disable=too-many-public-methods, too-many-lines
29
class TestEVC():
30
    """Tests to verify EVC class."""
31 1
32
    def setup_method(self):
33 1
        """Setup method"""
34
        attributes = {
35
            "controller": get_controller_mock(),
36
            "name": "circuit_for_tests",
37
            "uni_a": get_uni_mocked(is_valid=True),
38
            "uni_z": get_uni_mocked(is_valid=True),
39 1
        }
40
        self.evc_deploy = EVCDeploy(**attributes)
41 1
42
    def test_primary_links_zipped(self):
43
        """Test primary links zipped method."""
44 1
45 1
    @staticmethod
46 1
    @patch("napps.kytos.mef_eline.models.evc.log")
47
    def test_should_deploy_case1(log_mock):
48 1
        """Test should deploy method without primary links."""
49 1
        log_mock.debug.return_value = True
50
        attributes = {
51
            "controller": get_controller_mock(),
52
            "name": "custom_name",
53
            "uni_a": get_uni_mocked(is_valid=True),
54
            "uni_z": get_uni_mocked(is_valid=True),
55
        }
56 1
57 1
        evc = EVC(**attributes)
58 1
        evc.should_deploy()
59
        log_mock.debug.assert_called_with("Path is empty.")
60 1
61 1 View Code Duplication
    @patch("napps.kytos.mef_eline.models.evc.log")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
62
    def test_should_deploy_case2(self, log_mock):
63 1
        """Test should deploy method with disable circuit."""
64 1
        log_mock.debug.return_value = True
65
        attributes = {
66
            "controller": get_controller_mock(),
67
            "name": "custom_name",
68
            "uni_a": get_uni_mocked(is_valid=True),
69
            "uni_z": get_uni_mocked(is_valid=True),
70
            "primary_links": [get_link_mocked(), get_link_mocked()],
71 1
        }
72
        evc = EVC(**attributes)
73 1
74 1
        assert evc.should_deploy(attributes["primary_links"]) is False
75
        log_mock.debug.assert_called_with(f"{evc} is disabled.")
76 1
77 1 View Code Duplication
    @patch("napps.kytos.mef_eline.models.evc.log")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
78
    def test_should_deploy_case3(self, log_mock):
79 1
        """Test should deploy method with enabled and not active circuit."""
80 1
        log_mock.debug.return_value = True
81
        attributes = {
82
            "controller": get_controller_mock(),
83
            "name": "custom_name",
84
            "uni_a": get_uni_mocked(is_valid=True),
85
            "uni_z": get_uni_mocked(is_valid=True),
86
            "primary_links": [get_link_mocked(), get_link_mocked()],
87
            "enabled": True,
88 1
        }
89 1
        evc = EVC(**attributes)
90 1
        assert evc.should_deploy(attributes["primary_links"]) is True
91
        log_mock.debug.assert_called_with(f"{evc} will be deployed.")
92 1
93 1
    @patch("napps.kytos.mef_eline.models.evc.log")
94
    def test_should_deploy_case4(self, log_mock):
95 1
        """Test should deploy method with enabled and active circuit."""
96 1
        log_mock.debug.return_value = True
97
        attributes = {
98
            "controller": get_controller_mock(),
99
            "name": "custom_name",
100
            "uni_a": get_uni_mocked(is_valid=True),
101
            "uni_z": get_uni_mocked(is_valid=True),
102
            "primary_links": [get_link_mocked(), get_link_mocked()],
103
            "enabled": True,
104
            "active": True,
105 1
        }
106 1
        evc = EVC(**attributes)
107
        assert evc.should_deploy(attributes["primary_links"]) is False
108 1
109 1
    @patch("napps.kytos.mef_eline.models.evc.requests")
110
    def test_send_flow_mods_case1(self, requests_mock):
111 1
        """Test if you are sending flow_mods."""
112 1
        flow_mods = {"id": 20}
113
        switch = Mock(spec=Switch, id=1)
114 1
115 1
        response = MagicMock()
116 1
        response.status_code = 201
117
        requests_mock.post.return_value = response
118
119 1
        # pylint: disable=protected-access
120
        EVC._send_flow_mods(switch.id, flow_mods)
121 1
122 1
        expected_endpoint = f"{MANAGER_URL}/flows/{switch.id}"
123 1
        expected_data = {"flows": flow_mods, "force": False}
124 1
        assert requests_mock.post.call_count == 1
125
        requests_mock.post.assert_called_once_with(
126
            expected_endpoint, json=expected_data
127
        )
128 1
129 1
    @patch("napps.kytos.mef_eline.models.evc.requests")
130
    def test_send_flow_mods_case2(self, requests_mock):
131 1
        """Test if you are sending flow_mods."""
132 1
        flow_mods = {"id": 20}
133 1
        switch = Mock(spec=Switch, id=1)
134 1
        response = MagicMock()
135 1
        response.status_code = 201
136
        requests_mock.post.return_value = response
137
138 1
        # pylint: disable=protected-access
139
        EVC._send_flow_mods(switch.id, flow_mods, command='delete', force=True)
140 1
141 1
        expected_endpoint = f"{MANAGER_URL}/delete/{switch.id}"
142 1
        expected_data = {"flows": flow_mods, "force": True}
143 1
        assert requests_mock.post.call_count == 1
144
        requests_mock.post.assert_called_once_with(
145
            expected_endpoint, json=expected_data
146
        )
147 1
148 1
    @patch("napps.kytos.mef_eline.models.evc.requests")
149
    def test_send_flow_mods_error(self, requests_mock):
150 1
        """Test flow_manager call fails."""
151 1
        flow_mods = {"id": 20}
152 1
        switch = Mock(spec=Switch, id=1)
153 1
        response = MagicMock()
154 1
        response.status_code = 415
155
        requests_mock.post.return_value = response
156
157 1
        # pylint: disable=protected-access
158 1
        with pytest.raises(FlowModException):
159
            EVC._send_flow_mods(
160
                switch.id,
161
                flow_mods,
162
                command='delete',
163
                force=True
164
            )
165 1
166
    def test_prepare_flow_mod(self):
167 1
        """Test prepare flow_mod method."""
168 1
        interface_a = Interface("eth0", 1, Mock(spec=Switch))
169 1
        interface_z = Interface("eth1", 3, Mock(spec=Switch))
170
        attributes = {
171
            "table_group": {"epl": 0, "evpl": 0},
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 1
        }
180
        evc = EVC(**attributes)
181
182 1
        # pylint: disable=protected-access
183 1
        flow_mod = evc._prepare_flow_mod(interface_a, interface_z)
184
        expected_flow_mod = {
185
            "match": {"in_port": interface_a.port_number},
186
            "cookie": evc.get_cookie(),
187
            "owner": "mef_eline",
188
            "actions": [
189
                {"action_type": "output", "port": interface_z.port_number}
190
            ],
191
            "priority": EVPL_SB_PRIORITY,
192
            "table_group": "evpl",
193
            "table_id": 0,
194 1
        }
195
        assert expected_flow_mod == flow_mod
196 1
197
        evc.sb_priority = 1234
198 1
        flow_mod = evc._prepare_flow_mod(interface_a, interface_z, 3)
199
        assert flow_mod["priority"] == 1234
200
        assert flow_mod["actions"][1]["action_type"] == "set_queue"
201
        assert flow_mod["actions"][1]["queue_id"] == 3
202
203
    def test_prepare_pop_flow(self):
204
        """Test prepare pop flow  method."""
205 1
        attributes = {
206 1
            "table_group": {"epl": 0, "evpl": 0},
207 1
            "controller": get_controller_mock(),
208 1
            "name": "custom_name",
209
            "uni_a": get_uni_mocked(interface_port=1, is_valid=True),
210
            "uni_z": get_uni_mocked(interface_port=2, is_valid=True),
211 1
        }
212
        evc = EVC(**attributes)
213
        interface_a = evc.uni_a.interface
214
        interface_z = evc.uni_z.interface
215 1
        in_vlan = 10
216
217
        # pylint: disable=protected-access
218
        flow_mod = evc._prepare_pop_flow(
219
            interface_a, interface_z, in_vlan
220
        )
221
222
        expected_flow_mod = {
223
            "match": {"in_port": interface_a.port_number,
224
                      "dl_vlan": in_vlan},
225
            "cookie": evc.get_cookie(),
226
            "owner": "mef_eline",
227
            "actions": [
228 1
                {"action_type": "pop_vlan"},
229
                {"action_type": "output", "port": interface_z.port_number},
230
            ],
231 1
            "priority": EVPL_SB_PRIORITY,
232
            "table_group": "evpl",
233
            "table_id": 0,
234
        }
235
        assert expected_flow_mod == flow_mod
236
237
    # pylint: disable=too-many-branches
238
    @pytest.mark.parametrize(
239
        "in_vlan_a,in_vlan_z",
240
        [
241
            (100, 50),
242
            (100, 100),
243
            (100, "4096/4096"),
244
            (100, 0),
245
            (100, None),
246
            ("4096/4096", 50),
247
            ("4096/4096", "4096/4096"),
248
            ("4096/4096", 0),
249
            ("4096/4096", None),
250
            (0, 50),
251
            (0, "4096/4096"),
252
            (0, 0),
253 1
            (0, None),
254
            (None, 50),
255 1
            (None, "4096/4096"),
256
            (None, 0),
257
            (None, None),
258
        ]
259
    )
260
    def test_prepare_push_flow(self, in_vlan_a, in_vlan_z):
261
        """Test prepare push flow method."""
262 1
        attributes = {
263 1
            "table_group": {"evpl": 3, "epl": 4},
264 1
            "controller": get_controller_mock(),
265 1
            "name": "custom_name",
266
            "uni_a": get_uni_mocked(interface_port=1, is_valid=True),
267
            "uni_z": get_uni_mocked(interface_port=2, is_valid=True),
268 1
        }
269
        evc = EVC(**attributes)
270
        interface_a = evc.uni_a.interface
271 1
        interface_z = evc.uni_z.interface
272
        out_vlan_a = 20
273
274
        # pylint: disable=protected-access
275
        flow_mod = evc._prepare_push_flow(interface_a, interface_z,
276
                                          in_vlan_a, out_vlan_a,
277
                                          in_vlan_z)
278
        expected_flow_mod = {
279
            'match': {'in_port': interface_a.port_number},
280
            'cookie': evc.get_cookie(),
281
            'owner': 'mef_eline',
282
            'table_id': 3,
283
            'table_group': 'evpl',
284
            'actions': [
285
                {'action_type': 'push_vlan', 'tag_type': 's'},
286
                {'action_type': 'set_vlan', 'vlan_id': out_vlan_a},
287 1
                {
288 1
                    'action_type': 'output',
289 1
                    'port': interface_z.port_number
290 1
                }
291 1
            ],
292
            "priority": EVPL_SB_PRIORITY,
293 1
        }
294 1
        expected_flow_mod["priority"] = evc.get_priority(in_vlan_a)
295 1
        if in_vlan_a is not None:
296 1
            expected_flow_mod['match']['dl_vlan'] = in_vlan_a
297 1
        if in_vlan_z not in evc.special_cases and in_vlan_a != in_vlan_z:
298 1
            new_action = {"action_type": "set_vlan",
299 1
                          "vlan_id": in_vlan_z}
300 1
            expected_flow_mod["actions"].insert(0, new_action)
301 1
        if in_vlan_a not in evc.special_cases:
302 1
            if in_vlan_z == 0:
303 1
                new_action = {"action_type": "pop_vlan"}
304 1
                expected_flow_mod["actions"].insert(0, new_action)
305 1
        elif in_vlan_a == "4096/4096":
306 1
            if in_vlan_z == 0:
307 1
                new_action = {"action_type": "pop_vlan"}
308
                expected_flow_mod["actions"].insert(0, new_action)
309 1
        elif not in_vlan_a:
310 1
            if in_vlan_a is None:
311
                expected_flow_mod["table_group"] = "epl"
312 1
                expected_flow_mod["table_id"] = 4
313 1
            if in_vlan_z not in evc.special_cases:
314 1
                new_action = {"action_type": "push_vlan",
315
                              "tag_type": "c"}
316
                expected_flow_mod["actions"].insert(0, new_action)
317
        assert expected_flow_mod == flow_mod
318
319 1
    @staticmethod
320
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
321
    def test_install_uni_flows(send_flow_mods_mock):
322 1
        """Test install uni flows method.
323 1
324
        This test will verify the flows send to the send_flow_mods method.
325
        """
326 1
        evc = TestEVC.create_evc_inter_switch()
327
328 1
        # pylint: disable=protected-access
329
        evc._install_uni_flows()
330
        send_flow_mods_mock.assert_not_called()
331
332
        # pylint: disable=protected-access
333
        evc._install_uni_flows(evc.primary_links)
334
335
        expected_flow_mod_a = [
336
            {
337
                "match": {
338
                    "in_port": evc.uni_a.interface.port_number,
339
                    "dl_vlan": evc.uni_a.user_tag.value,
340
                },
341
                "cookie": evc.get_cookie(),
342
                "owner": "mef_eline",
343
                "table_group": "evpl",
344
                "table_id": 0,
345
                "actions": [
346
                    {
347
                        "action_type": "set_vlan",
348
                        "vlan_id": evc.uni_z.user_tag.value
349
                    },
350
                    {"action_type": "push_vlan", "tag_type": "s"},
351
                    {
352
                        "action_type": "set_vlan",
353
                        "vlan_id": evc.primary_links[0]
354
                        .get_metadata("s_vlan")
355
                        .value,
356
                    },
357
                    {
358
                        "action_type": "output",
359
                        "port": evc.primary_links[0].endpoint_a.port_number,
360
                    },
361
                ],
362
                "priority": EVPL_SB_PRIORITY,
363
            },
364
            {
365
                "match": {
366
                    "in_port": evc.primary_links[0].endpoint_a.port_number,
367
                    "dl_vlan": evc.primary_links[0]
368
                    .get_metadata("s_vlan")
369
                    .value,
370
                },
371
                "cookie": evc.get_cookie(),
372
                "owner": "mef_eline",
373
                "table_group": "evpl",
374
                "table_id": 0,
375
                "actions": [
376
                    {"action_type": "pop_vlan"},
377
                    {
378
                        "action_type": "output",
379 1
                        "port": evc.uni_a.interface.port_number,
380
                    },
381
                ],
382
                "priority": EVPL_SB_PRIORITY,
383 1
            },
384
        ]
385
386
        send_flow_mods_mock.assert_any_call(
387
            evc.uni_a.interface.switch.id, expected_flow_mod_a
388
        )
389
390
        expected_flow_mod_z = [
391
            {
392
                "match": {
393
                    "in_port": evc.uni_z.interface.port_number,
394
                    "dl_vlan": evc.uni_z.user_tag.value,
395
                },
396
                "cookie": evc.get_cookie(),
397
                "owner": "mef_eline",
398
                "table_group": "evpl",
399
                "table_id": 0,
400
                "actions": [
401
                    {
402
                        "action_type": "set_vlan",
403
                        "vlan_id": evc.uni_a.user_tag.value
404
                    },
405
                    {"action_type": "push_vlan", "tag_type": "s"},
406
                    {
407
                        "action_type": "set_vlan",
408
                        "vlan_id": evc.primary_links[-1]
409
                        .get_metadata("s_vlan")
410
                        .value,
411
                    },
412
                    {
413
                        "action_type": "output",
414
                        "port": evc.primary_links[-1].endpoint_b.port_number,
415
                    },
416
                ],
417
                "priority": EVPL_SB_PRIORITY,
418
            },
419
            {
420
                "match": {
421
                    "in_port": evc.primary_links[-1].endpoint_b.port_number,
422
                    "dl_vlan": evc.primary_links[-1]
423
                    .get_metadata("s_vlan")
424
                    .value,
425
                },
426
                "cookie": evc.get_cookie(),
427
                "owner": "mef_eline",
428
                "table_group": "evpl",
429
                "table_id": 0,
430
                "actions": [
431
                    {"action_type": "pop_vlan"},
432
                    {
433
                        "action_type": "output",
434 1
                        "port": evc.uni_z.interface.port_number,
435
                    },
436
                ],
437
                "priority": EVPL_SB_PRIORITY,
438 1
            },
439 1
        ]
440
441 1
        send_flow_mods_mock.assert_any_call(
442
            evc.uni_z.interface.switch.id, expected_flow_mod_z
443
        )
444
445
    @staticmethod
446
    def create_evc_inter_switch(tag_value_a=82, tag_value_z=83):
447
        """Create inter-switch EVC with two links in the path"""
448 1
        uni_a = get_uni_mocked(
449
            interface_port=2,
450
            tag_value=tag_value_a,
451
            switch_id=1,
452
            switch_dpid=1,
453
            is_valid=True,
454
        )
455
        uni_z = get_uni_mocked(
456 1
            interface_port=3,
457
            tag_value=tag_value_z,
458
            switch_id=3,
459
            switch_dpid=3,
460
            is_valid=True,
461
        )
462
463
        attributes = {
464
            "controller": get_controller_mock(),
465
            "name": "custom_name",
466
            "id": "1",
467
            "uni_a": uni_a,
468
            "uni_z": uni_z,
469
            "primary_links": [
470
                get_link_mocked(
471
                    switch_a=Switch(1),
472
                    switch_b=Switch(2),
473
                    endpoint_a_port=9,
474
                    endpoint_b_port=10,
475
                    metadata={"s_vlan": 5},
476
                ),
477
                get_link_mocked(
478
                    switch_a=Switch(2),
479
                    switch_b=Switch(3),
480 1
                    endpoint_a_port=11,
481
                    endpoint_b_port=12,
482 1
                    metadata={"s_vlan": 6},
483 1
                ),
484 1
            ],
485
            "table_group": {"epl": 0, "evpl": 0}
486
        }
487
        return EVC(**attributes)
488
489 1
    @staticmethod
490
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
491
    def test_install_nni_flows(send_flow_mods_mock):
492 1
        """Test install nni flows method.
493
494 1
        This test will verify the flows send to the send_flow_mods method.
495 1
        """
496
        evc = TestEVC.create_evc_inter_switch()
497 1
498 1
        # pylint: disable=protected-access
499
        evc._install_nni_flows(evc.primary_links)
500 1
501
        in_vlan = evc.primary_links[0].get_metadata("s_vlan").value
502
        out_vlan = evc.primary_links[-1].get_metadata("s_vlan").value
503
504
        in_port = evc.primary_links[0].endpoint_b.port_number
505
        out_port = evc.primary_links[-1].endpoint_a.port_number
506
507
        expected_flow_mods = [
508
            {
509
                "match": {"in_port": in_port, "dl_vlan": in_vlan},
510
                "cookie": evc.get_cookie(),
511
                "owner": "mef_eline",
512
                "table_group": "evpl",
513
                "table_id": 0,
514
                "actions": [
515
                    {"action_type": "set_vlan", "vlan_id": out_vlan},
516
                    {"action_type": "output", "port": out_port},
517
                ],
518
                "priority": EVPL_SB_PRIORITY
519
            },
520
            {
521
                "match": {"in_port": out_port, "dl_vlan": out_vlan},
522
                "cookie": evc.get_cookie(),
523
                "owner": "mef_eline",
524
                "table_group": "evpl",
525
                "table_id": 0,
526
                "actions": [
527 1
                    {"action_type": "set_vlan", "vlan_id": in_vlan},
528 1
                    {"action_type": "output", "port": in_port},
529
                ],
530 1
                "priority": EVPL_SB_PRIORITY,
531 1
            },
532 1
        ]
533 1
534 1
        dpid = evc.primary_links[0].endpoint_b.switch.id
535 1
        send_flow_mods_mock.assert_called_once_with(dpid, expected_flow_mods)
536 1
537 1
    @patch("requests.post")
538 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
539 1
    @patch("napps.kytos.mef_eline.models.evc.log")
540
    @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans")
541
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows")
542 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows")
543
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_direct_uni_flows")
544
    @patch("napps.kytos.mef_eline.models.evc.EVC.activate")
545
    @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy")
546
    def test_deploy_successfully(self, *args):
547
        """Test if all methods to deploy are called."""
548
        # pylint: disable=too-many-locals
549
        (
550
            should_deploy_mock,
551
            activate_mock,
552
            install_direct_uni_flows_mock,
553
            install_uni_flows_mock,
554 1
            install_nni_flows,
555 1
            chose_vlans_mock,
556 1
            log_mock,
557
            _,
558 1
            requests_mock,
559 1
        ) = args
560 1
561
        response = MagicMock()
562 1
        response.status_code = 201
563 1
        requests_mock.return_value = response
564 1
565 1
        should_deploy_mock.return_value = True
566 1
        evc = self.create_evc_inter_switch()
567 1
        deployed = evc.deploy_to_path(evc.primary_links)
568 1
569
        assert should_deploy_mock.call_count == 1
570
        assert activate_mock.call_count == 1
571 1
        assert install_uni_flows_mock.call_count == 1
572 1
        assert install_nni_flows.call_count == 1
573 1
        assert chose_vlans_mock.call_count == 1
574 1
        log_mock.info.assert_called_with(f"{evc} was deployed.")
575 1
        assert deployed is True
576 1
577
        # intra switch EVC
578 1
        evc = self.create_evc_intra_switch()
579 1
        assert evc.deploy_to_path(evc.primary_links) is True
580 1
        assert install_direct_uni_flows_mock.call_count == 1
581 1
        assert activate_mock.call_count == 2
582 1
        assert log_mock.info.call_count == 2
583 1
        log_mock.info.assert_called_with(f"{evc} was deployed.")
584 1
585 1
    @patch("requests.post")
586 1
    @patch("napps.kytos.mef_eline.models.evc.log")
587 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.discover_new_paths")
588
    @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans")
589
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows")
590 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows")
591
    @patch("napps.kytos.mef_eline.models.evc.EVC.activate")
592
    @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy")
593
    @patch("napps.kytos.mef_eline.models.EVC.sync")
594
    def test_deploy_fail(self, *args):
595
        """Test if all methods is ignored when the should_deploy is false."""
596
        # pylint: disable=too-many-locals
597
        (
598
            sync_mock,
599
            should_deploy_mock,
600
            activate_mock,
601
            install_uni_flows_mock,
602 1
            install_nni_flows,
603 1
            choose_vlans_mock,
604 1
            discover_new_paths_mock,
605
            log_mock,
606 1
            requests_mock,
607 1
        ) = args
608 1
609 1
        response = MagicMock()
610
        response.status_code = 201
611 1
        requests_mock.return_value = response
612 1
613 1
        evc = self.create_evc_inter_switch()
614 1
        should_deploy_mock.return_value = False
615 1
        discover_new_paths_mock.return_value = []
616 1
        deployed = evc.deploy_to_path()
617 1
618 1
        assert discover_new_paths_mock.call_count == 1
619 1
        assert should_deploy_mock.call_count == 1
620
        assert activate_mock.call_count == 0
621
        assert install_uni_flows_mock.call_count == 0
622 1
        assert install_nni_flows.call_count == 0
623 1
        assert choose_vlans_mock.call_count == 0
624 1
        assert log_mock.info.call_count == 0
625
        assert sync_mock.call_count == 1
626
        assert deployed is False
627 1
628 1
        # NoTagAvailable on static path
629 1
        should_deploy_mock.return_value = True
630 1
        choose_vlans_mock.side_effect = KytosNoTagAvailableError("error")
631
        assert evc.deploy_to_path(evc.primary_links) is False
632 1
633 1
        # NoTagAvailable on dynamic path
634
        should_deploy_mock.return_value = False
635
        discover_new_paths_mock.return_value = [Path(['a', 'b'])]
636
        choose_vlans_mock.side_effect = KytosNoTagAvailableError("error")
637 1
        assert evc.deploy_to_path(evc.primary_links) is False
638 1
639 1
    @patch("napps.kytos.mef_eline.models.evc.log")
640 1
    @patch(
641 1
        "napps.kytos.mef_eline.models.evc.EVC.discover_new_paths",
642 1
        return_value=[],
643
    )
644
    @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans")
645 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows")
646
    @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy")
647
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_current_flows")
648
    @patch("napps.kytos.mef_eline.models.evc.EVC.sync")
649
    def test_deploy_error(self, *args):
650
        """Test if all methods is ignored when the should_deploy is false."""
651
        # pylint: disable=too-many-locals
652
        (
653
            sync_mock,
654
            remove_current_flows,
655 1
            should_deploy_mock,
656 1
            install_nni_flows,
657 1
            choose_vlans_mock,
658
            discover_new_paths,
659
            log_mock,
660
        ) = args
661
662
        install_nni_flows.side_effect = FlowModException
663 1
        should_deploy_mock.return_value = True
664
        uni_a = get_uni_mocked(
665
            interface_port=2,
666
            tag_value=82,
667
            switch_id="switch_uni_a",
668
            is_valid=True,
669
        )
670 1
        uni_z = get_uni_mocked(
671
            interface_port=3,
672
            tag_value=83,
673
            switch_id="switch_uni_z",
674
            is_valid=True,
675
        )
676
677
        primary_links = [
678
            get_link_mocked(
679 1
                endpoint_a_port=9, endpoint_b_port=10, metadata={"s_vlan": 5}
680
            ),
681
            get_link_mocked(
682
                endpoint_a_port=11, endpoint_b_port=12, metadata={"s_vlan": 6}
683
            ),
684
        ]
685
686
        attributes = {
687
            "controller": get_controller_mock(),
688 1
            "name": "custom_name",
689 1
            "uni_a": uni_a,
690 1
            "uni_z": uni_z,
691
            "primary_links": primary_links,
692 1
            "queue_id": 5,
693
        }
694 1
        # Setup path to deploy
695
        path = Path()
696 1
        path.append(primary_links[0])
697 1
        path.append(primary_links[1])
698 1
699 1
        evc = EVC(**attributes)
700 1
701 1
        deployed = evc.deploy_to_path(path)
702 1
703 1
        assert discover_new_paths.call_count == 0
704
        assert should_deploy_mock.call_count == 1
705 1
        assert install_nni_flows.call_count == 1
706 1
        assert choose_vlans_mock.call_count == 1
707 1
        assert log_mock.error.call_count == 1
708 1
        assert sync_mock.call_count == 0
709 1
        assert remove_current_flows.call_count == 2
710 1
        assert deployed is False
711
712 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.get_failover_path_candidates")
713
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows")
714
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows")
715
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_path_flows")
716
    @patch("napps.kytos.mef_eline.models.EVC.sync")
717
    def test_setup_failover_path(self, *args):
718
        """Test setup_failover_path method."""
719
        (
720
            sync_mock,
721 1
            remove_path_flows_mock,
722
            install_uni_flows_mock,
723 1
            install_nni_flows_mock,
724 1
            get_failover_path_candidates_mock,
725
        ) = args
726
727 1
        # case1: early return intra switch
728 1
        evc1 = self.create_evc_intra_switch()
729
730 1
        assert evc1.setup_failover_path() is False
731 1
        assert sync_mock.call_count == 0
732
733
        # case2: early return not eligible for path failover
734 1
        evc2 = self.create_evc_inter_switch()
735 1
        evc2.is_eligible_for_failover_path = MagicMock(return_value=False)
736 1
737 1
        assert evc2.setup_failover_path() is False
738 1
        assert sync_mock.call_count == 0
739
740 1
        # case3: success failover_path setup
741 1
        evc2.is_eligible_for_failover_path = MagicMock(return_value=True)
742 1
        evc2.failover_path = ["link1", "link2"]
743 1
        path_mock = MagicMock()
744 1
        path_mock.__iter__.return_value = ["link3"]
745 1
        get_failover_path_candidates_mock.return_value = [None, path_mock]
746 1
747
        assert evc2.setup_failover_path() is True
748
        remove_path_flows_mock.assert_called_with(["link1", "link2"])
749 1
        path_mock.choose_vlans.assert_called()
750 1
        install_nni_flows_mock.assert_called_with(path_mock)
751 1
        install_uni_flows_mock.assert_called_with(path_mock, skip_in=True)
752
        assert evc2.failover_path == path_mock
753 1
        assert sync_mock.call_count == 1
754 1
755 1
        # case 4: failed to setup failover_path - No Tag available
756
        evc2.failover_path = []
757
        path_mock.choose_vlans.side_effect = KytosNoTagAvailableError("error")
758 1
        sync_mock.call_count = 0
759 1
760 1
        assert evc2.setup_failover_path() is False
761 1
        assert len(list(evc2.failover_path)) == 0
762
        assert sync_mock.call_count == 1
763 1
764 1
        # case 5: failed to setup failover_path - FlowMod exception
765 1
        evc2.failover_path = []
766 1
        path_mock.choose_vlans.side_effect = None
767
        install_nni_flows_mock.side_effect = FlowModException("error")
768 1
        sync_mock.call_count = 0
769 1
770 1
        assert evc2.setup_failover_path() is False
771
        assert len(list(evc2.failover_path)) == 0
772
        assert sync_mock.call_count == 1
773
        remove_path_flows_mock.assert_called_with(path_mock)
774 1
775 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy_to_path")
776
    @patch("napps.kytos.mef_eline.models.evc.EVC.discover_new_paths")
777 1
    def test_deploy_to_backup_path1(
778 1
        self, discover_new_paths_mocked, deploy_to_path_mocked
779 1
    ):
780
        """Test deployment when dynamic_backup_path is False in same switch"""
781 1
        uni_a = get_uni_mocked(interface_port=2, tag_value=82, is_valid=True)
782
        uni_z = get_uni_mocked(interface_port=3, tag_value=83, is_valid=True)
783
784
        switch = Mock(spec=Switch)
785
        uni_a.interface.switch = switch
786
        uni_z.interface.switch = switch
787
788
        attributes = {
789
            "controller": get_controller_mock(),
790 1
            "name": "custom_name",
791 1
            "uni_a": uni_a,
792 1
            "uni_z": uni_z,
793
            "enabled": True,
794 1
            "dynamic_backup_path": False,
795
        }
796 1
797 1
        evc = EVC(**attributes)
798
        discover_new_paths_mocked.return_value = []
799 1
        deploy_to_path_mocked.return_value = True
800 1
801 1
        deployed = evc.deploy_to_backup_path()
802 1
803 1
        deploy_to_path_mocked.assert_called_once_with()
804 1
        assert deployed is True
805 1
806 1
    @patch("requests.post")
807 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
808 1
    @patch("napps.kytos.mef_eline.models.evc.log")
809
    @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans")
810
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows")
811 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows")
812
    @patch("napps.kytos.mef_eline.models.evc.EVC.activate")
813
    @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy")
814
    @patch("napps.kytos.mef_eline.models.evc.EVC.discover_new_paths")
815
    def test_deploy_without_path_case1(self, *args):
816
        """Test if not path is found a dynamic path is used."""
817
        # pylint: disable=too-many-locals
818
        (
819
            discover_new_paths_mocked,
820
            should_deploy_mock,
821
            activate_mock,
822
            install_uni_flows_mock,
823 1
            install_nni_flows,
824 1
            chose_vlans_mock,
825 1
            log_mock,
826
            _,
827 1
            requests_mock,
828 1
        ) = args
829
830
        response = MagicMock()
831
        response.status_code = 201
832
        requests_mock.return_value = response
833
834 1
        should_deploy_mock.return_value = False
835
        uni_a = get_uni_mocked(
836
            interface_port=2,
837
            tag_value=82,
838
            switch_id="switch_uni_a",
839
            is_valid=True,
840
        )
841 1
        uni_z = get_uni_mocked(
842
            interface_port=3,
843
            tag_value=83,
844
            switch_id="switch_uni_z",
845
            is_valid=True,
846
        )
847
848
        attributes = {
849
            "controller": get_controller_mock(),
850 1
            "name": "custom_name",
851
            "uni_a": uni_a,
852
            "uni_z": uni_z,
853
            "enabled": True,
854
            "dynamic_backup_path": False,
855
        }
856
857
        dynamic_backup_path = Path(
858
            [
859
                get_link_mocked(
860
                    endpoint_a_port=9,
861
                    endpoint_b_port=10,
862
                    metadata={"s_vlan": 5},
863
                ),
864
                get_link_mocked(
865 1
                    endpoint_a_port=11,
866 1
                    endpoint_b_port=12,
867
                    metadata={"s_vlan": 6},
868 1
                ),
869
            ]
870 1
        )
871 1
872 1
        evc = EVC(**attributes)
873 1
        discover_new_paths_mocked.return_value = [dynamic_backup_path]
874 1
875 1
        deployed = evc.deploy_to_path()
876 1
877 1
        assert should_deploy_mock.call_count == 1
878
        assert discover_new_paths_mocked.call_count == 1
879 1
        assert activate_mock.call_count == 1
880 1
        assert install_uni_flows_mock.call_count == 1
881 1
        assert install_nni_flows.call_count == 1
882 1
        assert chose_vlans_mock.call_count == 1
883
        log_mock.info.assert_called_with(f"{evc} was deployed.")
884 1
        assert deployed is True
885
886
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.deploy_to_primary_path")
887 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.deploy_to_backup_path")
888 1
    @patch("napps.kytos.mef_eline.models.evc.emit_event")
889 1
    def test_deploy(self, *args):
890 1
        """Test method deploy"""
891
        (emit_event_mock, deploy_primary_mock, deploy_backup_mock) = args
892
893 1
        # case 1: deploy to primary
894 1
        self.evc_deploy.archived = False
895 1
        deploy_primary_mock.return_value = True
896 1
        assert self.evc_deploy.deploy()
897
        assert emit_event_mock.call_count == 1
898
899 1
        # case 2: deploy to backup
900 1
        deploy_primary_mock.return_value = False
901 1
        deploy_backup_mock.return_value = True
902
        assert self.evc_deploy.deploy()
903
        assert emit_event_mock.call_count == 2
904 1
905 1
        # case 3: fail to deploy to primary and backup
906 1
        deploy_backup_mock.return_value = False
907
        assert self.evc_deploy.deploy() is False
908 1
        assert emit_event_mock.call_count == 2
909 1
910 1
        # case 4: archived
911 1
        self.evc_deploy.archived = True
912
        assert self.evc_deploy.deploy() is False
913 1
        assert emit_event_mock.call_count == 2
914 1
915 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.remove_current_flows")
916 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.sync")
917 1
    @patch("napps.kytos.mef_eline.models.evc.emit_event")
918 1
    def test_remove(self, *args):
919
        """Test method remove"""
920 1
        (emit_event_mock, sync_mock, remove_flows_mock) = args
921 1
        self.evc_deploy.remove()
922 1
        remove_flows_mock.assert_called()
923 1
        sync_mock.assert_called()
924
        emit_event_mock.assert_called()
925
        assert self.evc_deploy.is_enabled() is False
926 1
927 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
928
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
929
    @patch("napps.kytos.mef_eline.models.evc.log.error")
930
    def test_remove_current_flows(self, *args):
931
        """Test remove current flows."""
932
        # pylint: disable=too-many-locals
933 1
        (log_error_mock, send_flow_mods_mocked, _) = args
934
        uni_a = get_uni_mocked(
935
            interface_port=2,
936
            tag_value=82,
937
            switch_id="switch_uni_a",
938
            is_valid=True,
939
        )
940 1
        uni_z = get_uni_mocked(
941 1
            interface_port=3,
942 1
            tag_value=83,
943
            switch_id="switch_uni_z",
944 1
            is_valid=True,
945
        )
946
947
        switch_a = Switch("00:00:00:00:00:01")
948
        switch_b = Switch("00:00:00:00:00:02")
949
        switch_c = Switch("00:00:00:00:00:03")
950
951
        attributes = {
952
            "controller": get_controller_mock(),
953
            "name": "custom_name",
954
            "uni_a": uni_a,
955
            "uni_z": uni_z,
956
            "active": True,
957
            "enabled": True,
958
            "primary_links": [
959
                get_link_mocked(
960
                    switch_a=switch_a,
961
                    switch_b=switch_b,
962
                    endpoint_a_port=9,
963
                    endpoint_b_port=10,
964
                    metadata={"s_vlan": 5},
965
                ),
966
                get_link_mocked(
967
                    switch_a=switch_b,
968
                    switch_b=switch_c,
969 1
                    endpoint_a_port=11,
970
                    endpoint_b_port=12,
971 1
                    metadata={"s_vlan": 6},
972 1
                ),
973
            ],
974 1
        }
975 1
976 1
        evc = EVC(**attributes)
977
978
        evc.current_path = evc.primary_links
979 1
        evc.remove_current_flows()
980 1
981 1
        assert send_flow_mods_mocked.call_count == 5
982
        assert evc.is_active() is False
983 1
        flows = [
984
            {"cookie": evc.get_cookie(), "cookie_mask": 18446744073709551615}
985
        ]
986 1
        switch_1 = evc.primary_links[0].endpoint_a.switch
987 1
        switch_2 = evc.primary_links[0].endpoint_b.switch
988 1
        send_flow_mods_mocked.assert_any_call(switch_1.id, flows, 'delete',
989
                                              force=True)
990 1
        send_flow_mods_mocked.assert_any_call(switch_2.id, flows, 'delete',
991 1
                                              force=True)
992 1
993 1
        send_flow_mods_mocked.side_effect = FlowModException("error")
994
        evc.remove_current_flows()
995
        log_error_mock.assert_called()
996 1
997 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
998
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
999
    @patch("napps.kytos.mef_eline.models.evc.log.error")
1000
    def test_remove_failover_flows_exclude_uni_switches(self, *args):
1001
        """Test remove failover flows excluding UNI switches."""
1002
        # pylint: disable=too-many-locals
1003 1
        (log_error_mock, send_flow_mods_mocked, mock_upsert) = args
1004
        uni_a = get_uni_mocked(
1005
            interface_port=2,
1006
            tag_value=82,
1007
            switch_id="00:00:00:00:00:00:00:01",
1008
            is_valid=True,
1009
        )
1010 1
        uni_z = get_uni_mocked(
1011 1
            interface_port=3,
1012 1
            tag_value=83,
1013
            switch_id="00:00:00:00:00:00:00:03",
1014 1
            is_valid=True,
1015
        )
1016
1017
        switch_a = Switch("00:00:00:00:00:00:00:01")
1018
        switch_b = Switch("00:00:00:00:00:00:00:02")
1019
        switch_c = Switch("00:00:00:00:00:00:00:03")
1020
1021
        attributes = {
1022
            "controller": get_controller_mock(),
1023
            "name": "custom_name",
1024
            "uni_a": uni_a,
1025
            "uni_z": uni_z,
1026
            "active": True,
1027
            "enabled": True,
1028
            "failover_path": [
1029
                get_link_mocked(
1030
                    switch_a=switch_a,
1031
                    switch_b=switch_b,
1032
                    endpoint_a_port=9,
1033
                    endpoint_b_port=10,
1034
                    metadata={"s_vlan": 5},
1035
                ),
1036
                get_link_mocked(
1037
                    switch_a=switch_b,
1038
                    switch_b=switch_c,
1039 1
                    endpoint_a_port=11,
1040 1
                    endpoint_b_port=12,
1041
                    metadata={"s_vlan": 6},
1042 1
                ),
1043 1
            ],
1044
        }
1045
1046
        evc = EVC(**attributes)
1047 1
        evc.remove_failover_flows(exclude_uni_switches=True, sync=True)
1048
1049 1
        assert send_flow_mods_mocked.call_count == 1
1050
        flows = [
1051 1
            {"cookie": evc.get_cookie(),
1052 1
             "cookie_mask": int(0xffffffffffffffff)}
1053 1
        ]
1054
        send_flow_mods_mocked.assert_any_call(switch_b.id, flows, 'delete',
1055 1
                                              force=True)
1056 1
        assert mock_upsert.call_count == 1
1057 1
1058
        send_flow_mods_mocked.side_effect = FlowModException("error")
1059
        evc.remove_current_flows()
1060 1
        log_error_mock.assert_called()
1061 1
1062
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1063
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
1064
    def test_remove_failover_flows_include_all(self, *args):
1065
        """Test remove failover flows including UNI switches."""
1066
        # pylint: disable=too-many-locals
1067 1
        (send_flow_mods_mocked, mock_upsert) = args
1068
        uni_a = get_uni_mocked(
1069
            interface_port=2,
1070
            tag_value=82,
1071
            switch_id="00:00:00:00:00:00:00:01",
1072
            is_valid=True,
1073
        )
1074 1
        uni_z = get_uni_mocked(
1075 1
            interface_port=3,
1076 1
            tag_value=83,
1077
            switch_id="00:00:00:00:00:00:00:03",
1078 1
            is_valid=True,
1079
        )
1080
1081
        switch_a = Switch("00:00:00:00:00:00:00:01")
1082
        switch_b = Switch("00:00:00:00:00:00:00:02")
1083
        switch_c = Switch("00:00:00:00:00:00:00:03")
1084
1085
        attributes = {
1086
            "controller": get_controller_mock(),
1087
            "name": "custom_name",
1088
            "uni_a": uni_a,
1089
            "uni_z": uni_z,
1090
            "active": True,
1091
            "enabled": True,
1092
            "failover_path": [
1093
                get_link_mocked(
1094
                    switch_a=switch_a,
1095
                    switch_b=switch_b,
1096
                    endpoint_a_port=9,
1097
                    endpoint_b_port=10,
1098
                    metadata={"s_vlan": 5},
1099
                ),
1100
                get_link_mocked(
1101
                    switch_a=switch_b,
1102
                    switch_b=switch_c,
1103 1
                    endpoint_a_port=11,
1104 1
                    endpoint_b_port=12,
1105
                    metadata={"s_vlan": 6},
1106 1
                ),
1107 1
            ],
1108
        }
1109
1110
        evc = EVC(**attributes)
1111 1
        evc.remove_failover_flows(exclude_uni_switches=False, sync=True)
1112
1113 1
        assert send_flow_mods_mocked.call_count == 3
1114
        flows = [
1115 1
            {"cookie": evc.get_cookie(),
1116
             "cookie_mask": int(0xffffffffffffffff)}
1117 1
        ]
1118
        send_flow_mods_mocked.assert_any_call(switch_a.id, flows, 'delete',
1119 1
                                              force=True)
1120 1
        send_flow_mods_mocked.assert_any_call(switch_b.id, flows, 'delete',
1121
                                              force=True)
1122 1
        send_flow_mods_mocked.assert_any_call(switch_c.id, flows, 'delete',
1123 1
                                              force=True)
1124 1
        assert mock_upsert.call_count == 1
1125 1
1126 1
    @staticmethod
1127 1
    def create_evc_intra_switch():
1128
        """Create intra-switch EVC."""
1129
        switch = Mock(spec=Switch)
1130
        switch.dpid = 2
1131 1
        switch.id = switch.dpid
1132
        interface_a = Interface("eth0", 1, switch)
1133
        interface_z = Interface("eth1", 3, switch)
1134
        uni_a = get_uni_mocked(
1135 1
            tag_value=82,
1136 1
            is_valid=True,
1137 1
        )
1138
        uni_z = get_uni_mocked(
1139
            tag_value=84,
1140
            is_valid=True,
1141
        )
1142
        uni_a.interface = interface_a
1143
        uni_z.interface = interface_z
1144
        attributes = {
1145
            "table_group": {"epl": 0, "evpl": 0},
1146 1
            "controller": get_controller_mock(),
1147
            "name": "custom_name",
1148
            "id": "1",
1149 1
            "uni_a": uni_a,
1150
            "uni_z": uni_z,
1151
            "enabled": True,
1152
        }
1153
        return EVC(**attributes)
1154
1155
    # pylint: disable=too-many-branches
1156
    @pytest.mark.parametrize(
1157
        "uni_a,uni_z",
1158
        [
1159
            (100, 50),
1160
            (100, "4096/4096"),
1161
            (100, 0),
1162
            (100, None),
1163
            ("4096/4096", 50),
1164
            ("4096/4096", "4096/4096"),
1165
            ("4096/4096", 0),
1166
            ("4096/4096", None),
1167
            (0, 50),
1168
            (0, "4096/4096"),
1169
            (0, 0),
1170 1
            (0, None),
1171 1
            (None, 50),
1172
            (None, "4096/4096"),
1173 1
            (None, 0),
1174 1
            (None, None),
1175
        ]
1176 1
    )
1177
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
1178
    def test_deploy_direct_uni_flows(self, send_flow_mods_mock, uni_a, uni_z):
1179
        """Test _install_direct_uni_flows"""
1180
        evc = TestEVC.create_evc_intra_switch()
1181
        expected_dpid = evc.uni_a.interface.switch.id
1182
1183
        expected_flows = [
1184
            {
1185
                "match": {"in_port": 1},
1186
                "cookie": evc.get_cookie(),
1187
                "owner": "mef_eline",
1188
                "table_id": 0,
1189
                "table_group": "epl",
1190
                "actions": [
1191
                    {"action_type": "output", "port": 3},
1192
                ],
1193
                "priority": EPL_SB_PRIORITY
1194
            },
1195
            {
1196
                "match": {"in_port": 3},
1197
                "cookie": evc.get_cookie(),
1198
                "owner": "mef_eline",
1199
                "table_id": 0,
1200 1
                "table_group": "epl",
1201 1
                "actions": [
1202 1
                    {"action_type": "output", "port": 1},
1203 1
                ],
1204 1
                "priority": EPL_SB_PRIORITY
1205 1
            }
1206 1
        ]
1207 1
        evc.uni_a = get_uni_mocked(tag_value=uni_a, is_valid=True)
1208 1
        evc.uni_a.interface.port_number = 1
1209 1
        evc.uni_z = get_uni_mocked(tag_value=uni_z, is_valid=True)
1210 1
        evc.uni_z.interface.port_number = 3
1211 1
        expected_dpid = evc.uni_a.interface.switch.id
1212 1
        evc._install_direct_uni_flows()
1213 1
        if uni_a is not None:
1214 1
            expected_flows[0]["match"]["dl_vlan"] = uni_a
1215 1
            expected_flows[0]["table_group"] = "evpl"
1216
        if uni_z is not None:
1217
            expected_flows[1]["match"]["dl_vlan"] = uni_z
1218 1
            expected_flows[1]["table_group"] = "evpl"
1219 1
        expected_flows[0]["priority"] = EVC.get_priority(uni_a)
1220
        expected_flows[1]["priority"] = EVC.get_priority(uni_z)
1221
        if uni_z not in evc.special_cases:
1222
            expected_flows[0]["actions"].insert(
1223 1
                0, {"action_type": "set_vlan", "vlan_id": uni_z}
1224 1
            )
1225
        if uni_a not in evc.special_cases:
1226
            expected_flows[1]["actions"].insert(
1227
                    0, {"action_type": "set_vlan",
1228 1
                        "vlan_id": uni_a}
1229 1
                )
1230 1
            if not uni_z:
1231 1
                expected_flows[1]["actions"].insert(
1232 1
                    0, {"action_type": "push_vlan",
1233 1
                        "tag_type": "c"}
1234 1
                )
1235 1
            if uni_z == 0:
1236 1
                new_action = {"action_type": "pop_vlan"}
1237 1
                expected_flows[0]["actions"].insert(0, new_action)
1238
        elif uni_a == "4096/4096":
1239
            if uni_z == 0:
1240
                new_action = {"action_type": "pop_vlan"}
1241 1
                expected_flows[0]["actions"].insert(0, new_action)
1242 1
        elif uni_a == 0:
1243 1
            if uni_z not in evc.special_cases:
1244 1
                expected_flows[0]["actions"].insert(
1245 1
                    0, {"action_type": "push_vlan",
1246 1
                        "tag_type": "c"}
1247
                )
1248
            if uni_z:
1249
                new_action = {"action_type": "pop_vlan"}
1250 1
                expected_flows[1]["actions"].insert(0, new_action)
1251
        elif uni_a is None:
1252
            if uni_z not in evc.special_cases:
1253
                expected_flows[0]["actions"].insert(
1254 1
                    0, {"action_type": "push_vlan",
1255
                        "tag_type": "c"}
1256 1
                )
1257 1
        send_flow_mods_mock.assert_called_with(
1258
            expected_dpid, expected_flows
1259 1
        )
1260
1261 1
    def test_is_affected_by_link(self):
1262 1
        """Test is_affected_by_link method"""
1263
        self.evc_deploy.current_path = Path(['a', 'b', 'c'])
1264 1
        assert self.evc_deploy.is_affected_by_link('b') is True
1265
1266 1
    def test_is_backup_path_affected_by_link(self):
1267 1
        """Test is_backup_path_affected_by_link method"""
1268
        self.evc_deploy.backup_path = Path(['a', 'b', 'c'])
1269 1
        assert self.evc_deploy.is_backup_path_affected_by_link('d') is False
1270
1271 1
    def test_is_primary_path_affected_by_link(self):
1272 1
        """Test is_primary_path_affected_by_link method"""
1273 1
        self.evc_deploy.primary_path = Path(['a', 'b', 'c'])
1274
        assert self.evc_deploy.is_primary_path_affected_by_link('c') is True
1275 1
1276
    def test_is_using_primary_path(self):
1277 1
        """Test is_using_primary_path method"""
1278 1
        self.evc_deploy.primary_path = Path(['a', 'b', 'c'])
1279 1
        self.evc_deploy.current_path = Path(['e', 'f', 'g'])
1280
        assert self.evc_deploy.is_using_primary_path() is False
1281 1
1282 1
    def test_is_using_backup_path(self):
1283
        """Test is_using_backup_path method"""
1284 1
        self.evc_deploy.backup_path = Path(['a', 'b', 'c'])
1285 1
        self.evc_deploy.current_path = Path(['e', 'f', 'g'])
1286 1
        assert self.evc_deploy.is_using_backup_path() is False
1287 1
1288
    @patch('napps.kytos.mef_eline.models.path.Path.status')
1289 1
    def test_is_using_dynamic_path(self, mock_status):
1290
        """Test is_using_dynamic_path method"""
1291 1
        mock_status.return_value = False
1292 1
        self.evc_deploy.backup_path = Path([])
1293 1
        self.evc_deploy.primary_path = Path([])
1294
        assert self.evc_deploy.is_using_dynamic_path() is False
1295
1296
    def test_get_path_status(self):
1297 1
        """Test get_path_status method"""
1298 1
        path = Path([])
1299
        assert self.evc_deploy.get_path_status(path) == EntityStatus.DISABLED
1300
        path = Path([
1301
            get_link_mocked(status=EntityStatus.UP),
1302 1
            get_link_mocked(status=EntityStatus.DOWN)
1303
        ])
1304 1
        assert self.evc_deploy.get_path_status(path) == EntityStatus.DOWN
1305 1
        path = Path([
1306
            get_link_mocked(status=EntityStatus.UP),
1307 1
            get_link_mocked(status=EntityStatus.UP)
1308 1
        ])
1309 1
        assert self.evc_deploy.get_path_status(path) == EntityStatus.UP
1310
1311 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._prepare_uni_flows")
1312 1
    def test_get_failover_flows(self, prepare_uni_flows_mock):
1313 1
        """Test get_failover_flows method."""
1314 1
        evc = self.create_evc_inter_switch()
1315
        evc.failover_path = Path([])
1316 1
        assert len(evc.get_failover_flows()) == 0
1317 1
1318 1
        path = MagicMock()
1319 1
        evc.failover_path = path
1320
        evc.get_failover_flows()
1321 1
        prepare_uni_flows_mock.assert_called_with(path, skip_out=True)
1322
1323
    @patch("napps.kytos.mef_eline.models.evc.log")
1324
    @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods")
1325
    @patch("napps.kytos.mef_eline.models.path.Path.make_vlans_available")
1326
    def test_remove_path_flows(self, *args):
1327 1
        """Test remove path flows."""
1328
        (
1329 1
            make_vlans_available_mock,
1330 1
            send_flow_mods_mock,
1331
            log_mock,
1332 1
        ) = args
1333
1334
        evc = self.create_evc_inter_switch()
1335
1336
        evc.remove_path_flows()
1337
        make_vlans_available_mock.assert_not_called()
1338
1339 1
        expected_flows_1 = [
1340
            {
1341
                'cookie': 12249790986447749121,
1342
                'cookie_mask': 18446744073709551615,
1343
                'match': {'in_port': 9, 'dl_vlan':  5}
1344
            },
1345
        ]
1346
        expected_flows_2 = [
1347
            {
1348
                'cookie': 12249790986447749121,
1349
                'cookie_mask': 18446744073709551615,
1350
                'match': {'in_port': 10, 'dl_vlan': 5}
1351 1
            },
1352
            {
1353
                'cookie': 12249790986447749121,
1354
                'cookie_mask': 18446744073709551615,
1355
                'match': {'in_port': 11, 'dl_vlan': 6}
1356
            },
1357
        ]
1358
        expected_flows_3 = [
1359 1
            {
1360 1
                'cookie': 12249790986447749121,
1361
                'cookie_mask': 18446744073709551615,
1362
                'match': {'in_port': 12, 'dl_vlan': 6}
1363
            },
1364
        ]
1365
1366 1
        evc.remove_path_flows(evc.primary_links)
1367 1
        send_flow_mods_mock.assert_has_calls([
1368 1
            call(1, expected_flows_1, 'delete', force=True),
1369
            call(2, expected_flows_2, 'delete', force=True),
1370 1
            call(3, expected_flows_3, 'delete', force=True),
1371 1
        ], any_order=True)
1372
1373 1
        send_flow_mods_mock.side_effect = FlowModException("err")
1374 1
        evc.remove_path_flows(evc.primary_links)
1375 1
        log_mock.error.assert_called()
1376 1
1377 1
    @patch("requests.put")
1378
    def test_run_bulk_sdntraces(self, put_mock):
1379 1
        """Test run_bulk_sdntraces method for bulk request."""
1380 1
        evc = self.create_evc_inter_switch()
1381
        response = MagicMock()
1382
        response.status_code = 200
1383
        response.json.return_value = {"result": "ok"}
1384
        put_mock.return_value = response
1385
1386
        expected_endpoint = f"{SDN_TRACE_CP_URL}/traces"
1387
        expected_payload = [
1388 1
                            {
1389 1
                                'trace': {
1390
                                    'switch': {'dpid': 1, 'in_port': 2},
1391
                                    'eth': {'dl_type': 0x8100, 'dl_vlan': 82}
1392
                                }
1393
                            }
1394 1
                        ]
1395
        arg_tuple = [(evc.uni_a.interface, evc.uni_a.user_tag.value)]
1396 1
        result = EVCDeploy.run_bulk_sdntraces(arg_tuple)
1397 1
        put_mock.assert_called_with(
1398 1
                                    expected_endpoint,
1399
                                    json=expected_payload,
1400 1
                                    timeout=30
1401 1
                                )
1402
        assert result['result'] == "ok"
1403 1
1404 1
        response.status_code = 400
1405 1
        result = EVCDeploy.run_bulk_sdntraces(arg_tuple)
1406 1
        assert result == {"result": []}
1407
1408 1
        put_mock.side_effect = Timeout
1409 1
        response.status_code = 200
1410
        result = EVCDeploy.run_bulk_sdntraces(arg_tuple)
1411
        assert result == {"result": []}
1412
1413
    @patch("requests.put")
1414
    def test_run_bulk_sdntraces_special_vlan(self, put_mock):
1415
        """Test run_bulk_sdntraces method for bulk request."""
1416
        evc = self.create_evc_inter_switch()
1417 1
        response = MagicMock()
1418 1
        response.status_code = 200
1419 1
        put_mock.return_value = response
1420
1421
        expected_endpoint = f"{SDN_TRACE_CP_URL}/traces"
1422
        expected_payload = [
1423
                            {
1424 1
                                'trace': {
1425 1
                                    'switch': {'dpid': 1, 'in_port': 2}
1426
                                }
1427 1
                            }
1428 1
                        ]
1429 1
        evc.uni_a.user_tag.value = 'untagged'
1430
        EVCDeploy.run_bulk_sdntraces(
1431
            [(evc.uni_a.interface, evc.uni_a.user_tag.value)]
1432
        )
1433
        put_mock.assert_called_with(
1434 1
                                    expected_endpoint,
1435 1
                                    json=expected_payload,
1436
                                    timeout=30
1437 1
                                )
1438 1
        args = put_mock.call_args[1]['json'][0]
1439 1
        assert 'eth' not in args
1440
1441
        evc.uni_a.user_tag.value = 0
1442
        EVCDeploy.run_bulk_sdntraces(
1443
            [(evc.uni_a.interface, evc.uni_a.user_tag.value)]
1444 1
        )
1445 1
        put_mock.assert_called_with(
1446
                                    expected_endpoint,
1447 1
                                    json=expected_payload,
1448 1
                                    timeout=30
1449 1
                                )
1450 1
        args = put_mock.call_args[1]['json'][0]['trace']
1451
        assert 'eth' not in args
1452
1453
        evc.uni_a.user_tag.value = '5/2'
1454
        EVCDeploy.run_bulk_sdntraces(
1455 1
            [(evc.uni_a.interface, evc.uni_a.user_tag.value)]
1456 1
        )
1457
        put_mock.assert_called_with(
1458 1
                                    expected_endpoint,
1459 1
                                    json=expected_payload,
1460 1
                                    timeout=30
1461
                                )
1462
        args = put_mock.call_args[1]['json'][0]['trace']
1463
        assert 'eth' not in args
1464
1465 1
        expected_payload[0]['trace']['eth'] = {'dl_type': 0x8100, 'dl_vlan': 1}
1466 1
        evc.uni_a.user_tag.value = 'any'
1467
        EVCDeploy.run_bulk_sdntraces(
1468 1
            [(evc.uni_a.interface, evc.uni_a.user_tag.value)]
1469
        )
1470
        put_mock.assert_called_with(
1471
                                    expected_endpoint,
1472 1
                                    json=expected_payload,
1473 1
                                    timeout=30
1474 1
                                )
1475
        args = put_mock.call_args[1]['json'][0]['trace']
1476
        assert args['eth'] == {'dl_type': 33024, 'dl_vlan': 1}
1477
1478
        evc.uni_a.user_tag.value = '4096/4096'
1479 1
        EVCDeploy.run_bulk_sdntraces(
1480 1
            [(evc.uni_a.interface, evc.uni_a.user_tag.value)]
1481
        )
1482 1
        put_mock.assert_called_with(
1483
                                    expected_endpoint,
1484
                                    json=expected_payload,
1485
                                    timeout=30
1486 1
                                )
1487 1
        args = put_mock.call_args[1]['json'][0]['trace']
1488 1
        assert args['eth'] == {'dl_type': 33024, 'dl_vlan': 1}
1489
1490
        expected_payload[0]['trace']['eth'] = {
1491
            'dl_type': 0x8100,
1492
            'dl_vlan': 10
1493 1
            }
1494 1
        evc.uni_a.user_tag.value = '10/10'
1495
        EVCDeploy.run_bulk_sdntraces(
1496 1
            [(evc.uni_a.interface, evc.uni_a.user_tag.value)]
1497
        )
1498
        put_mock.assert_called_with(
1499
                                    expected_endpoint,
1500 1
                                    json=expected_payload,
1501 1
                                    timeout=30
1502 1
                                )
1503
        args = put_mock.call_args[1]['json'][0]['trace']
1504
        assert args['eth'] == {'dl_type': 33024, 'dl_vlan': 10}
1505
1506
        expected_payload[0]['trace']['eth'] = {
1507
            'dl_type': 0x8100,
1508 1
            'dl_vlan': 1
1509 1
            }
1510 1
        evc.uni_a.user_tag.value = '5/3'
1511
        EVCDeploy.run_bulk_sdntraces(
1512 1
            [(evc.uni_a.interface, evc.uni_a.user_tag.value)]
1513
        )
1514 1
        put_mock.assert_called_with(
1515 1
                                    expected_endpoint,
1516 1
                                    json=expected_payload,
1517
                                    timeout=30
1518 1
                                )
1519
        args = put_mock.call_args[1]['json'][0]['trace']
1520
        assert args['eth'] == {'dl_type': 33024, 'dl_vlan': 1}
1521
1522
        expected_payload[0]['trace']['eth'] = {
1523
            'dl_type': 0x8100,
1524
            'dl_vlan': 10
1525
            }
1526
        evc.uni_a.user_tag.value = 10
1527
        EVCDeploy.run_bulk_sdntraces(
1528
            [(evc.uni_a.interface, evc.uni_a.user_tag.value)]
1529
        )
1530
        put_mock.assert_called_with(
1531
                                    expected_endpoint,
1532
                                    json=expected_payload,
1533
                                    timeout=30
1534
                                )
1535 1
1536
    @patch("napps.kytos.mef_eline.models.evc.log")
1537
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.run_bulk_sdntraces")
1538
    def test_check_list_traces(self, run_bulk_sdntraces_mock, _):
1539
        """Test check_list_traces method."""
1540
        evc = self.create_evc_inter_switch()
1541
1542
        for link in evc.primary_links:
1543
            link.metadata['s_vlan'] = MagicMock(value=link.metadata['s_vlan'])
1544
        evc.current_path = evc.primary_links
1545
1546
        trace_a = [
1547
            {
1548
                "dpid": 1,
1549
                "port": 2,
1550
                "time": "t1",
1551
                "type": "starting",
1552
                "vlan": 82
1553 1
            },
1554
            {
1555
                "dpid": 2,
1556 1
                "port": 10,
1557 1
                "time": "t2",
1558
                "type": "intermediary",
1559
                "vlan": 5
1560 1
            },
1561
            {"dpid": 3, "port": 12, "time": "t3", "type": "last", "vlan": 6},
1562
        ]
1563
        trace_z = [
1564
            {
1565
                "dpid": 3,
1566 1
                "port": 3,
1567 1
                "time": "t1",
1568
                "type": "starting",
1569
                "vlan": 83
1570 1
            },
1571
            {
1572
                "dpid": 2,
1573
                "port": 11,
1574
                "time": "t2",
1575
                "type": "intermediary",
1576 1
                "vlan": 6
1577 1
            },
1578
            {"dpid": 1, "port": 9, "time": "t3", "type": "last", "vlan": 5},
1579
        ]
1580 1
1581 1
        run_bulk_sdntraces_mock.return_value = {
1582 1
                                                "result": [trace_a, trace_z]
1583
                                            }
1584
        result = EVCDeploy.check_list_traces([evc])
1585 1
        assert result[evc.id] is True
1586 1
1587
        # case2: fail incomplete trace from uni_a
1588
        run_bulk_sdntraces_mock.return_value = {
1589 1
                                                "result": [
1590 1
                                                            trace_a[:2],
1591
                                                            trace_z
1592
                                                        ]
1593 1
        }
1594 1
        result = EVCDeploy.check_list_traces([evc])
1595
        assert result[evc.id] is False
1596
1597 1
        # case3: fail incomplete trace from uni_z
1598 1
        run_bulk_sdntraces_mock.return_value = {
1599 1
                                                "result": [
1600 1
                                                            trace_a,
1601
                                                            trace_z[:2]
1602
                                                        ]
1603 1
        }
1604 1
        result = EVCDeploy.check_list_traces([evc])
1605 1
        assert result[evc.id] is False
1606 1
1607 1
        # case4: fail wrong vlan id in trace from uni_a
1608 1
        trace_a[1]["vlan"] = 5
1609 1
        trace_z[1]["vlan"] = 99
1610
        run_bulk_sdntraces_mock.return_value = {
1611
                                                "result": [trace_a, trace_z]
1612 1
        }
1613 1
        result = EVCDeploy.check_list_traces([evc])
1614 1
        assert result[evc.id] is False
1615 1
1616
        # case5: fail wrong vlan id in trace from uni_z
1617
        trace_a[1]["vlan"] = 99
1618 1
        run_bulk_sdntraces_mock.return_value = {
1619 1
                                                "result": [trace_a, trace_z]
1620 1
        }
1621 1
        result = EVCDeploy.check_list_traces([evc])
1622 1
        assert result[evc.id] is False
1623 1
1624 1
        # case6: success when no output in traces
1625 1
        trace_a[1]["vlan"] = 5
1626
        trace_z[1]["vlan"] = 6
1627 1
        result = EVCDeploy.check_list_traces([evc])
1628 1
        assert result[evc.id] is True
1629 1
1630
        # case7: fail when output is None in trace_a or trace_b
1631 1
        trace_a[-1]["out"] = None
1632
        result = EVCDeploy.check_list_traces([evc])
1633 1
        assert result[evc.id] is False
1634 1
        trace_a[-1].pop("out", None)
1635 1
        trace_z[-1]["out"] = None
1636
        result = EVCDeploy.check_list_traces([evc])
1637 1
        assert result[evc.id] is False
1638
1639
        # case8: success when the output is correct on both uni
1640
        trace_a[-1]["out"] = {"port": 3, "vlan": 83}
1641
        trace_z[-1]["out"] = {"port": 2, "vlan": 82}
1642
        result = EVCDeploy.check_list_traces([evc])
1643
        assert result[evc.id] is True
1644
1645
        # case9: fail if any output is incorrect
1646
        trace_a[-1]["out"] = {"port": 3, "vlan": 99}
1647
        trace_z[-1]["out"] = {"port": 2, "vlan": 82}
1648
        result = EVCDeploy.check_list_traces([evc])
1649
        assert result[evc.id] is False
1650
        trace_a[-1]["out"] = {"port": 3, "vlan": 83}
1651
        trace_z[-1]["out"] = {"port": 2, "vlan": 99}
1652
        result = EVCDeploy.check_list_traces([evc])
1653
        assert result[evc.id] is False
1654
1655 View Code Duplication
    @patch("napps.kytos.mef_eline.models.evc.log")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1656
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.run_bulk_sdntraces")
1657
    def test_check_list_traces_any_cases(self, run_bulk_sdntraces_mock, _):
1658
        """Test check_list_traces method."""
1659
        evc = self.create_evc_inter_switch("any", "any")
1660
1661 1
        for link in evc.primary_links:
1662
            link.metadata['s_vlan'] = MagicMock(value=link.metadata['s_vlan'])
1663
        evc.current_path = evc.primary_links
1664
1665
        trace_a = [
1666
            {
1667
                "dpid": 1,
1668
                "port": 2,
1669
                "time": "t1",
1670
                "type": "starting",
1671
                "vlan": 1
1672
            },
1673
            {
1674
                "dpid": 2,
1675
                "port": 10,
1676
                "time": "t2",
1677
                "type": "intermediary",
1678
                "vlan": 5
1679
            },
1680
            {
1681
                "dpid": 3,
1682
                "port": 12,
1683
                'out': {'port': 3, 'vlan': 1},
1684
                "time": "t3",
1685
                "type": "last",
1686 1
                "vlan": 6
1687
            },
1688
        ]
1689 1
        trace_z = [
1690 1
            {
1691
                "dpid": 3,
1692 1
                "port": 3,
1693 1
                "time": "t1",
1694 1
                "type": "starting",
1695
                "vlan": 1
1696 1
            },
1697
            {
1698 1
                "dpid": 2,
1699 1
                "port": 11,
1700 1
                "time": "t2",
1701
                "type": "intermediary",
1702 1
                "vlan": 6
1703
            },
1704
            {
1705
                "dpid": 1,
1706
                "port": 9,
1707
                'out': {'port': 2, 'vlan': 1},
1708
                "time": "t3",
1709
                "type": "last",
1710
                "vlan": 5
1711
            },
1712
        ]
1713
1714
        run_bulk_sdntraces_mock.return_value = {
1715
                                                "result": [trace_a, trace_z]
1716
                                            }
1717
        result = EVCDeploy.check_list_traces([evc])
1718
        assert result[evc.id] is True
1719
1720 View Code Duplication
    @patch("napps.kytos.mef_eline.models.evc.log")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1721
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.run_bulk_sdntraces")
1722
    def test_check_list_traces_untagged_cases(self, bulk_sdntraces_mock, _):
1723
        """Test check_list_traces method."""
1724
        evc = self.create_evc_inter_switch("untagged", "untagged")
1725
1726 1
        for link in evc.primary_links:
1727
            link.metadata['s_vlan'] = MagicMock(value=link.metadata['s_vlan'])
1728
        evc.current_path = evc.primary_links
1729
1730
        trace_a = [
1731
            {
1732
                "dpid": 1,
1733
                "port": 2,
1734
                "time": "t1",
1735
                "type": "starting",
1736
                "vlan": 0
1737
            },
1738
            {
1739
                "dpid": 2,
1740
                "port": 10,
1741
                "time": "t2",
1742
                "type": "intermediary",
1743
                "vlan": 5
1744
            },
1745
            {
1746
                "dpid": 3,
1747
                "port": 12,
1748
                'out': {'port': 3},
1749
                "time": "t3", "type":
1750
                "last",
1751 1
                "vlan": 6
1752
                },
1753
        ]
1754 1
        trace_z = [
1755 1
            {
1756
                "dpid": 3,
1757 1
                "port": 3,
1758 1
                "time": "t1",
1759 1
                "type": "starting",
1760
                "vlan": 0
1761 1
            },
1762
            {
1763 1
                "dpid": 2,
1764 1
                "port": 11,
1765 1
                "time": "t2",
1766
                "type": "intermediary",
1767 1
                "vlan": 6
1768
            },
1769
            {
1770
                "dpid": 1,
1771
                "port": 9,
1772
                'out': {'port': 2},
1773
                "time": "t3",
1774
                "type": "last",
1775
                "vlan": 5
1776
            },
1777
        ]
1778
1779
        bulk_sdntraces_mock.return_value = {
1780
                                                "result": [trace_a, trace_z]
1781
                                            }
1782
        result = EVCDeploy.check_list_traces([evc])
1783
        assert result[evc.id] is True
1784 1
1785
    @patch("napps.kytos.mef_eline.models.evc.log")
1786
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.run_bulk_sdntraces")
1787
    def test_check_list_traces_invalid_types(self, run_bulk_sdntraces_mock, _):
1788
        """Test check_list_traces method for invalid traces by trace type."""
1789
        evc = self.create_evc_inter_switch()
1790
1791
        for link in evc.primary_links:
1792
            link.metadata['s_vlan'] = MagicMock(value=link.metadata['s_vlan'])
1793
        evc.current_path = evc.primary_links
1794
1795
        trace_a = [
1796
            {
1797
                "dpid": 1,
1798
                "port": 2,
1799
                "time": "t1",
1800
                "type": "starting",
1801
                "vlan": 82
1802
            },
1803
            {
1804
                "dpid": 2,
1805
                "port": 10,
1806
                "time": "t2",
1807
                "type": "intermediary",
1808 1
                "vlan": 5
1809
            },
1810
            {"dpid": 3, "port": 12, "time": "t3", "type": "last", "vlan": 6},
1811 1
        ]
1812
        trace_z = [
1813 1
            {
1814
                "dpid": 3,
1815 1
                "port": 3,
1816
                "time": "t1",
1817
                "type": "starting",
1818
                "vlan": 83
1819
            },
1820
            {
1821
                "dpid": 2,
1822
                "port": 11,
1823
                "time": "t2",
1824
                "type": "intermediary",
1825
                "vlan": 6
1826
            },
1827
            {
1828
                "dpid": 1,
1829
                "port": 9,
1830
                "time": "t3",
1831
                "type": "last",
1832 1
                "vlan": 5
1833
            },
1834
        ]
1835 1
1836
        run_bulk_sdntraces_mock.return_value = {
1837 1
                                                "result": [trace_a, trace_z]
1838
                                            }
1839 1
        result = EVCDeploy.check_list_traces([evc])
1840
1841
        assert result[evc.id] is True
1842
1843 1
        trace_z = [
1844
            {
1845 1
                "dpid": 3,
1846 1
                "port": 3,
1847
                "time": "t1",
1848 1
                "type": "starting",
1849
                "vlan": 83
1850 1
            },
1851 1
            {
1852 1
                "dpid": 2,
1853 1
                "port": 11,
1854 1
                "time": "t2",
1855 1
                "type": "loop",
1856
                "vlan": 6
1857
            },
1858 1
        ]
1859
1860 1
        run_bulk_sdntraces_mock.return_value = {
1861 1
                                                "result": [trace_a, trace_z]
1862 1
                                            }
1863 1
        result = EVCDeploy.check_list_traces([evc])
1864 1
        # type loop
1865
        assert result[evc.id] is False
1866 1
1867
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_trace")
1868 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_range")
1869 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.run_bulk_sdntraces")
1870 1
    def test_check_list_traces_vlan_list(self, *args):
1871
        """Test check_list_traces with vlan list"""
1872 1
        mock_bulk, mock_range, mock_trace = args
1873 1
        mask_list = [1, '2/4094', '4/4094']
1874 1
        evc = self.create_evc_inter_switch([[1, 5]], [[1, 5]])
1875
        evc.uni_a.user_tag.mask_list = mask_list
1876 1
        evc.uni_z.user_tag.mask_list = mask_list
1877 1
        mock_bulk.return_value = {"result": ["mock"] * 6}
1878 1
        mock_range.return_value = True
1879
        actual_return = EVC.check_list_traces([evc])
1880 1
        assert actual_return == {evc._id: True}
1881 1
        assert mock_trace.call_count == 0
1882 1
        assert mock_range.call_count == 1
1883
        args = mock_range.call_args[0]
1884 1
        assert args[0] == evc
1885
        assert args[1] == ["mock"] * 6
1886 1
1887 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_trace")
1888
    @patch("napps.kytos.mef_eline.models.evc.log")
1889 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.run_bulk_sdntraces")
1890 1
    def test_check_list_traces_empty(self, mock_bulk, mock_log, mock_trace):
1891
        """Test check_list_traces with empty return"""
1892 1
        evc = self.create_evc_inter_switch(1, 1)
1893 1
        actual_return = EVC.check_list_traces([])
1894
        assert not actual_return
1895 1
1896 1
        mock_bulk.return_value = {"result": []}
1897
        actual_return = EVC.check_list_traces([evc])
1898 1
        assert not actual_return
1899
1900 1
        mock_bulk.return_value = {"result": ["mock"]}
1901 1
        mock_trace.return_value = True
1902 1
        actual_return = EVC.check_list_traces([evc])
1903 1
        assert mock_log.error.call_count == 1
1904 1
        assert not actual_return
1905 1
1906 1
    @patch(
1907 1
        "napps.kytos.mef_eline.models.path.DynamicPathManager"
1908
        ".get_disjoint_paths"
1909 1
    )
1910
    def test_get_failover_path_vandidates(self, get_disjoint_paths_mock):
1911 1
        """Test get_failover_path_candidates method"""
1912 1
        self.evc_deploy.get_failover_path_candidates()
1913 1
        get_disjoint_paths_mock.assert_called_once()
1914 1
1915 1
    def test_is_failover_path_affected_by_link(self):
1916 1
        """Test is_failover_path_affected_by_link method"""
1917 1
        link1 = get_link_mocked(endpoint_a_port=1, endpoint_b_port=2)
1918
        link2 = get_link_mocked(endpoint_a_port=3, endpoint_b_port=4)
1919
        link3 = get_link_mocked(endpoint_a_port=5, endpoint_b_port=6)
1920
        self.evc_deploy.failover_path = Path([link1, link2])
1921
        assert self.evc_deploy.is_failover_path_affected_by_link(link1) is True
1922
        assert self.evc_deploy.is_failover_path_affected_by_link(link3) \
1923
               is False
1924
1925
    def test_is_eligible_for_failover_path(self):
1926
        """Test is_eligible_for_failover_path method"""
1927
        assert self.evc_deploy.is_eligible_for_failover_path() is False
1928
        self.evc_deploy.dynamic_backup_path = True
1929
        self.evc_deploy.primary_path = Path([])
1930
        self.evc_deploy.backup_path = Path([])
1931
        assert self.evc_deploy.is_eligible_for_failover_path() is True
1932
1933
    def test_get_value_from_uni_tag(self):
1934
        """Test _get_value_from_uni_tag"""
1935
        uni = get_uni_mocked(tag_value="any")
1936
        value = EVC._get_value_from_uni_tag(uni)
1937
        assert value == "4096/4096"
1938
1939
        uni.user_tag.value = "untagged"
1940
        value = EVC._get_value_from_uni_tag(uni)
1941
        assert value == 0
1942
1943
        uni.user_tag.value = 100
1944
        value = EVC._get_value_from_uni_tag(uni)
1945
        assert value == 100
1946
1947
        uni.user_tag = None
1948
        value = EVC._get_value_from_uni_tag(uni)
1949
        assert value is None
1950
1951
        uni = get_uni_mocked(tag_value=[[12, 20]])
1952
        uni.user_tag.mask_list = ['12/4092', '16/4092', '20/4094']
1953
1954
        value = EVC._get_value_from_uni_tag(uni)
1955
        assert value == ['12/4092', '16/4092', '20/4094']
1956
1957
    def test_get_priority(self):
1958
        """Test get_priority_from_vlan"""
1959
        evpl_value = EVC.get_priority(100)
1960
        assert evpl_value == EVPL_SB_PRIORITY
1961
1962
        untagged_value = EVC.get_priority(0)
1963
        assert untagged_value == UNTAGGED_SB_PRIORITY
1964
1965
        any_value = EVC.get_priority("4096/4096")
1966
        assert any_value == ANY_SB_PRIORITY
1967
1968
        epl_value = EVC.get_priority(None)
1969
        assert epl_value == EPL_SB_PRIORITY
1970
1971
        epl_value = EVC.get_priority([[1, 5]])
1972
        assert epl_value == EVPL_SB_PRIORITY
1973
1974
    def test_set_flow_table_group_id(self):
1975
        """Test set_flow_table_group_id"""
1976
        self.evc_deploy.table_group = {"epl": 3, "evpl": 4}
1977
        flow_mod = {}
1978
        self.evc_deploy.set_flow_table_group_id(flow_mod, 100)
1979
        assert flow_mod["table_group"] == "evpl"
1980
        assert flow_mod["table_id"] == 4
1981
        self.evc_deploy.set_flow_table_group_id(flow_mod, None)
1982
        assert flow_mod["table_group"] == "epl"
1983
        assert flow_mod["table_id"] == 3
1984
1985
    def test_get_endpoint_by_id(self):
1986
        """Test get_endpoint_by_id"""
1987
        link = MagicMock()
1988
        link.endpoint_a.switch.id = "01"
1989
        link.endpoint_b.switch.id = "02"
1990
        result = self.evc_deploy.get_endpoint_by_id(link, "01", operator.eq)
1991
        assert result == link.endpoint_a
1992
        result = self.evc_deploy.get_endpoint_by_id(link, "01", operator.ne)
1993
        assert result == link.endpoint_b
1994
1995
    @patch("napps.kytos.mef_eline.models.evc.EVC._prepare_pop_flow")
1996
    @patch("napps.kytos.mef_eline.models.evc.EVC.get_endpoint_by_id")
1997
    @patch("napps.kytos.mef_eline.models.evc.EVC._prepare_push_flow")
1998
    def test_prepare_uni_flows(self, mock_push, mock_endpoint, _):
1999
        """Test _prepare_uni_flows"""
2000
        mask_list = [1, '2/4094', '4/4094']
2001
        uni_a = get_uni_mocked(interface_port=1, tag_value=[[1, 5]])
2002
        uni_a.user_tag.mask_list = mask_list
2003
        uni_z = get_uni_mocked(interface_port=2, tag_value=[[1, 5]])
2004
        uni_z.user_tag.mask_list = mask_list
2005
        mock_endpoint.return_value = "mock_endpoint"
2006
        attributes = {
2007
            "table_group": {"evpl": 3, "epl": 4},
2008
            "controller": get_controller_mock(),
2009
            "name": "custom_name",
2010
            "uni_a": uni_a,
2011
            "uni_z": uni_z,
2012
        }
2013
        evc = EVC(**attributes)
2014
        link = get_link_mocked()
2015
        evc._prepare_uni_flows(Path([link]))
2016
        call_list = []
2017
        for i in range(0, 3):
2018
            call_list.append(call(
2019
                uni_a.interface,
2020
                "mock_endpoint",
2021
                mask_list[i],
2022
                None,
2023
                mask_list,
2024
                queue_id=-1
2025
            ))
2026
        for i in range(0, 3):
2027
            call_list.append(call(
2028
                uni_z.interface,
2029
                "mock_endpoint",
2030
                mask_list[i],
2031
                None,
2032
                mask_list,
2033
                queue_id=-1
2034
            ))
2035
        mock_push.assert_has_calls(call_list)
2036
2037
    def test_prepare_direct_uni_flows(self):
2038
        """Test _prepare_direct_uni_flows"""
2039
        mask_list = [1, '2/4094', '4/4094']
2040
        uni_a = get_uni_mocked(interface_port=1, tag_value=[[1, 5]])
2041
        uni_a.user_tag.mask_list = mask_list
2042
        uni_z = get_uni_mocked(interface_port=2, tag_value=[[1, 5]])
2043
        uni_z.user_tag.mask_list = mask_list
2044
        attributes = {
2045
            "table_group": {"evpl": 3, "epl": 4},
2046
            "controller": get_controller_mock(),
2047
            "name": "custom_name",
2048
            "uni_a": uni_a,
2049
            "uni_z": uni_z,
2050
        }
2051
        evc = EVC(**attributes)
2052
        flows = evc._prepare_direct_uni_flows()[1]
2053
        assert len(flows) == 6
2054
        for i in range(0, 3):
2055
            assert flows[i]["match"]["in_port"] == 1
2056
            assert flows[i]["match"]["dl_vlan"] == mask_list[i]
2057
            assert flows[i]["priority"] == EVPL_SB_PRIORITY
2058
        for i in range(3, 6):
2059
            assert flows[i]["match"]["in_port"] == 2
2060
            assert flows[i]["match"]["dl_vlan"] == mask_list[i-3]
2061
            assert flows[i]["priority"] == EVPL_SB_PRIORITY
2062
2063
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_trace")
2064
    def test_check_range(self, mock_check_range):
2065
        """Test check_range"""
2066
        mask_list = [1, '2/4094', '4/4094']
2067
        uni_a = get_uni_mocked(interface_port=1, tag_value=[[1, 5]])
2068
        uni_a.user_tag.mask_list = mask_list
2069
        uni_z = get_uni_mocked(interface_port=2, tag_value=[[1, 5]])
2070
        uni_z.user_tag.mask_list = mask_list
2071
        attributes = {
2072
            "table_group": {"evpl": 3, "epl": 4},
2073
            "controller": get_controller_mock(),
2074
            "name": "custom_name",
2075
            "uni_a": uni_a,
2076
            "uni_z": uni_z,
2077
        }
2078
        circuit = EVC(**attributes)
2079
        traces = list(range(0, 6))
2080
        mock_check_range.return_value = True
2081
        check = EVC.check_range(circuit, traces)
2082
        call_list = []
2083
        for i in range(0, 3):
2084
            call_list.append(call(
2085
                mask_list[i], mask_list[i],
2086
                uni_a.interface,
2087
                uni_z.interface,
2088
                circuit.current_path,
2089
                i*2, i*2+1
2090
            ))
2091
        mock_check_range.assert_has_calls(call_list)
2092
        assert check
2093
2094
        mock_check_range.side_effect = [True, False, True]
2095
        check = EVC.check_range(circuit, traces)
2096
        assert check is False
2097