Passed
Pull Request — master (#407)
by Vinicius
09:10 queued 05:00
created

build.tests.unit.models.test_evc_deploy   F

Complexity

Total Complexity 88

Size/Duplication

Total Lines 2097
Duplicated Lines 7.53 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 1557
dl 158
loc 2097
ccs 855
cts 855
cp 1
rs 0.8
c 0
b 0
f 0
wmc 88

55 Methods

Rating   Name   Duplication   Size   Complexity  
B TestEVC.test_check_list_traces_any_cases() 64 64 2
A TestEVC.create_evc_inter_switch() 0 43 1
A TestEVC.test_is_using_backup_path() 0 5 1
A TestEVC.test_is_using_primary_path() 0 5 1
B TestEVC.test_run_bulk_sdntraces_special_vlan() 0 121 1
A TestEVC.test_is_primary_path_affected_by_link() 0 4 1
A TestEVC.test_get_endpoint_by_id() 0 9 1
A TestEVC.test_prepare_pop_flow() 0 33 1
A TestEVC.test_remove() 0 11 1
A TestEVC.create_evc_intra_switch() 0 28 1
B TestEVC.test_deploy_successfully() 0 47 1
D TestEVC.test_prepare_push_flow() 0 80 11
B TestEVC.test_remove_failover_flows_exclude_uni_switches() 0 64 1
A TestEVC.test_get_failover_flows() 0 11 1
B TestEVC.test_deploy_fail() 0 53 1
A TestEVC.test_should_deploy_case1() 0 15 1
A TestEVC.test_deploy_to_backup_path1() 0 30 1
B TestEVC.test_remove_current_flows() 0 69 1
A TestEVC.test_send_flow_mods_case1() 0 18 1
A TestEVC.test_send_flow_mods_case2() 0 17 1
A TestEVC.test_prepare_flow_mod() 0 36 1
A TestEVC.test_prepare_direct_uni_flows() 0 25 3
B TestEVC.test_check_list_traces_invalid_types() 0 81 2
B TestEVC.test_check_list_traces() 0 118 2
A TestEVC.test_remove_path_flows() 0 53 1
A TestEVC.test_is_eligible_for_failover_path() 0 7 1
A TestEVC.test_check_list_traces_empty() 0 18 1
A TestEVC.test_check_range() 0 34 2
A TestEVC.test_get_priority() 0 16 1
B TestEVC.test_remove_failover_flows_include_all() 0 63 1
A TestEVC.test_install_nni_flows() 0 47 1
A TestEVC.test_should_deploy_case4() 0 15 1
A TestEVC.test_set_flow_table_group_id() 0 10 1
A TestEVC.test_is_failover_path_affected_by_link() 0 9 1
B TestEVC.test_deploy_error() 0 72 1
A TestEVC.test_primary_links_zipped() 0 2 1
A TestEVC.test_should_deploy_case2() 15 15 1
A TestEVC.setup_method() 0 9 1
A TestEVC.test_get_value_from_uni_tag() 0 23 1
A TestEVC.test_is_using_dynamic_path() 0 7 1
A TestEVC.test_is_backup_path_affected_by_link() 0 4 1
A TestEVC.test_deploy() 0 28 1
A TestEVC.test_send_flow_mods_error() 0 16 2
B TestEVC.test_deploy_without_path_case1() 0 79 1
A TestEVC.test_get_path_status() 0 14 1
A TestEVC.test_check_list_traces_vlan_list() 0 19 1
B TestEVC.test_check_list_traces_untagged_cases() 64 64 2
B TestEVC.test_setup_failover_path() 0 62 1
F TestEVC.test_deploy_direct_uni_flows() 0 103 14
A TestEVC.test_should_deploy_case3() 15 15 1
B TestEVC.test_prepare_uni_flows() 0 41 3
B TestEVC.test_install_uni_flows() 0 124 1
A TestEVC.test_get_failover_path_vandidates() 0 8 1
A TestEVC.test_is_affected_by_link() 0 4 1
A TestEVC.test_run_bulk_sdntraces() 0 35 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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