TestEVC.test_prepare_push_flow()   F
last analyzed

Complexity

Conditions 13

Size

Total Lines 86
Code Lines 74

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 13

Importance

Changes 0
Metric Value
cc 13
eloc 74
nop 3
dl 0
loc 86
ccs 29
cts 29
cp 1
crap 13
rs 3.7909
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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:

Complexity

Complex classes like build.tests.unit.models.test_evc_deploy.TestEVC.test_prepare_push_flow() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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