Passed
Pull Request — master (#571)
by Vinicius
04:22
created

TestEVC.test_install_nni_flows()   A

Complexity

Conditions 1

Size

Total Lines 50
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 1

Importance

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