Passed
Push — master ( 04ec80...a47e28 )
by Vinicius
04:04 queued 16s
created

TestEVC.test_install_flows()   A

Complexity

Conditions 1

Size

Total Lines 25
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

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