Passed
Pull Request — master (#570)
by Aldo
05:02
created

TestEVC.test_install_uni_flows()   B

Complexity

Conditions 1

Size

Total Lines 127
Code Lines 80

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 80
nop 1
dl 0
loc 127
ccs 13
cts 13
cp 1
crap 1
rs 7.6545
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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