TestMain.test_create_a_circuit_case_1()   B
last analyzed

Complexity

Conditions 1

Size

Total Lines 99
Code Lines 76

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 41
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 76
nop 10
dl 0
loc 99
ccs 41
cts 41
cp 1
crap 1
rs 7.7854
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
"""Module to test the main napp file."""
2 1
import asyncio
3 1
from unittest.mock import (AsyncMock, MagicMock, Mock, call,
4
                           create_autospec, patch)
5
6 1
import pytest
7 1
from kytos.lib.helpers import get_controller_mock, get_test_client
8 1
from kytos.core.helpers import now
9 1
from kytos.core.common import EntityStatus
10 1
from kytos.core.events import KytosEvent
11 1
from kytos.core.exceptions import KytosTagError
12 1
from kytos.core.interface import TAGRange, UNI, Interface
13 1
from napps.kytos.mef_eline.exceptions import FlowModException, InvalidPath
14 1
from napps.kytos.mef_eline.models import EVC, Path
15 1
from napps.kytos.mef_eline.tests.helpers import get_uni_mocked
16
17
18 1
async def test_on_table_enabled():
19
    """Test on_table_enabled"""
20
    # pylint: disable=import-outside-toplevel
21 1
    from napps.kytos.mef_eline.main import Main
22 1
    controller = get_controller_mock()
23 1
    controller.buffers.app.aput = AsyncMock()
24 1
    Main.get_eline_controller = MagicMock()
25 1
    napp = Main(controller)
26
27
    # Succesfully setting table groups
28 1
    content = {"mef_eline": {"epl": 2}}
29 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
30
                       content=content)
31 1
    await napp.on_table_enabled(event)
32 1
    assert napp.table_group["epl"] == 2
33 1
    assert napp.table_group["evpl"] == 0
34 1
    assert controller.buffers.app.aput.call_count == 1
35
36
    # Failure at setting table groups
37 1
    content = {"mef_eline": {"unknown": 123}}
38 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
39
                       content=content)
40 1
    await napp.on_table_enabled(event)
41 1
    assert controller.buffers.app.aput.call_count == 1
42
43
    # Failure with early return
44 1
    content = {}
45 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
46
                       content=content)
47 1
    await napp.on_table_enabled(event)
48 1
    assert controller.buffers.app.aput.call_count == 1
49
50
51
# pylint: disable=too-many-public-methods, too-many-lines
52
# pylint: disable=too-many-arguments,too-many-locals
53 1
class TestMain:
54
    """Test the Main class."""
55
56 1
    def setup_method(self):
57
        """Execute steps before each tests.
58
59
        Set the server_name_url_url from kytos/mef_eline
60
        """
61
62
        # The decorator run_on_thread is patched, so methods that listen
63
        # for events do not run on threads while tested.
64
        # Decorators have to be patched before the methods that are
65
        # decorated with them are imported.
66 1
        patch("kytos.core.helpers.run_on_thread", lambda x: x).start()
67
        # pylint: disable=import-outside-toplevel
68 1
        from napps.kytos.mef_eline.main import Main
69 1
        Main.get_eline_controller = MagicMock()
70 1
        controller = get_controller_mock()
71 1
        self.napp = Main(controller)
72 1
        self.api_client = get_test_client(controller, self.napp)
73 1
        self.base_endpoint = "kytos/mef_eline"
74
75 1
    def test_get_event_listeners(self):
76
        """Verify all event listeners registered."""
77 1
        expected_events = [
78
            "kytos/core.shutdown",
79
            "kytos/core.shutdown.kytos/mef_eline",
80
            "kytos/topology.link_up",
81
            "kytos/topology.link_down",
82
        ]
83 1
        actual_events = self.napp.listeners()
84
85 1
        for _event in expected_events:
86 1
            assert _event in actual_events, _event
87
88 1
    @patch('napps.kytos.mef_eline.main.log')
89 1
    @patch('napps.kytos.mef_eline.main.Main.execute_consistency')
90 1
    def test_execute(self, mock_execute_consistency, mock_log):
91
        """Test execute."""
92 1
        self.napp.execution_rounds = 0
93 1
        self.napp.execute()
94 1
        mock_execute_consistency.assert_called()
95 1
        assert mock_log.debug.call_count == 2
96
97
        # Test locked should return
98 1
        mock_execute_consistency.call_count = 0
99 1
        mock_log.info.call_count = 0
100
        # pylint: disable=protected-access
101 1
        self.napp._lock = MagicMock()
102 1
        self.napp._lock.locked.return_value = True
103
        # pylint: enable=protected-access
104 1
        self.napp.execute()
105 1
        mock_execute_consistency.assert_not_called()
106 1
        mock_log.info.assert_not_called()
107
108 1
    @patch("napps.kytos.mef_eline.main.map_evc_event_content")
109 1
    @patch("napps.kytos.mef_eline.main.emit_event")
110 1
    @patch('napps.kytos.mef_eline.main.settings')
111 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
112 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_list_traces")
113 1
    def test_execute_consistency(self, mock_check_list_traces, *args):
114
        """Test execute_consistency."""
115 1
        (
116
            mongo_controller_upsert_mock,
117
            mock_settings,
118
            mock_emit_event,
119
            mock_map_evc,
120
        ) = args
121
122 1
        mock_map_evc.side_effect = lambda x: x
123
124 1
        stored_circuits = {'1': {'name': 'circuit_1'},
125
                           '2': {'name': 'circuit_2'},
126
                           '3': {'name': 'circuit_3'}}
127 1
        mongo_controller_upsert_mock.return_value = True
128 1
        self.napp.mongo_controller.get_circuits.return_value = {
129
            "circuits": stored_circuits
130
        }
131
132 1
        mock_settings.WAIT_FOR_OLD_PATH = -1
133
134 1
        evc1 = MagicMock(id=1, service_level=0, creation_time=1)
135 1
        evc1.is_enabled.return_value = True
136 1
        evc1.is_active.return_value = False
137 1
        evc1.lock.locked.return_value = False
138 1
        evc1.has_recent_removed_flow.return_value = False
139 1
        evc1.is_recent_updated.return_value = False
140 1
        evc1.execution_rounds = 0
141
142 1
        evc2 = MagicMock(id=2, service_level=7, creation_time=1)
143 1
        evc2.is_enabled.return_value = True
144 1
        evc2.is_active.return_value = False
145 1
        evc2.lock.locked.return_value = False
146 1
        evc2.has_recent_removed_flow.return_value = False
147 1
        evc2.is_recent_updated.return_value = False
148 1
        evc2.execution_rounds = 0
149
150 1
        evc3 = MagicMock(id=3, service_level=0, creation_time=1)
151 1
        evc3.is_enabled.return_value = True
152 1
        evc3.is_active.return_value = True
153 1
        evc3.lock.locked.return_value = False
154 1
        evc3.has_recent_removed_flow.return_value = False
155 1
        evc3.is_recent_updated.return_value = False
156 1
        evc3.execution_rounds = 0
157 1
        evc3.is_eligible_for_failover_path.return_value = True
158 1
        evc3.failover_path = Path([])
159
160 1
        self.napp.circuits = {
161
            '1': evc1,
162
            '2': evc2,
163
            '3': evc3,
164
        }
165 1
        assert self.napp.get_evcs_by_svc_level() == [
166
            evc2,
167
            evc1,
168
            evc3
169
        ]
170
171 1
        mock_check_list_traces.return_value = {
172
            1: True,
173
            2: False,
174
            3: True,
175
        }
176
177 1
        self.napp.execute_consistency()
178 1
        assert evc1.activate.call_count == 1
179 1
        assert evc1.sync.call_count == 1
180 1
        assert evc2.deploy.call_count == 1
181
182 1
        mock_emit_event.assert_called_once_with(
183
            self.napp.controller,
184
            "need_failover",
185
            content=evc3
186
        )
187
188 1
    @patch('napps.kytos.mef_eline.main.settings')
189 1
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
190 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
191 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_list_traces")
192 1
    def test_execute_consistency_wait_for(self, mock_check_list_traces, *args):
193
        """Test execute and wait for setting."""
194 1
        (mongo_controller_upsert_mock, _, mock_settings) = args
195
196 1
        stored_circuits = {'1': {'name': 'circuit_1'}}
197 1
        mongo_controller_upsert_mock.return_value = True
198 1
        self.napp.mongo_controller.get_circuits.return_value = {
199
            "circuits": stored_circuits
200
        }
201
202 1
        mock_settings.WAIT_FOR_OLD_PATH = -1
203 1
        evc1 = MagicMock(id=1, service_level=0, creation_time=1)
204 1
        evc1.is_enabled.return_value = True
205 1
        evc1.is_active.return_value = False
206 1
        evc1.lock.locked.return_value = False
207 1
        evc1.has_recent_removed_flow.return_value = False
208 1
        evc1.is_recent_updated.return_value = False
209 1
        evc1.execution_rounds = 0
210 1
        evc1.deploy.call_count = 0
211 1
        self.napp.circuits = {'1': evc1}
212 1
        assert self.napp.get_evcs_by_svc_level() == [evc1]
213 1
        mock_settings.WAIT_FOR_OLD_PATH = 1
214
215 1
        mock_check_list_traces.return_value = {1: False}
216
217 1
        self.napp.execute_consistency()
218 1
        assert evc1.deploy.call_count == 0
219 1
        self.napp.execute_consistency()
220 1
        assert evc1.deploy.call_count == 1
221
222 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
223 1
    @patch('napps.kytos.mef_eline.models.evc.EVCBase._validate')
224 1
    def test_evc_from_dict(self, _validate_mock, uni_from_dict_mock):
225
        """
226
        Test the helper method that create an EVN from dict.
227
228
        Verify object creation with circuit data and schedule data.
229
        """
230 1
        _validate_mock.return_value = True
231 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
232 1
        payload = {
233
            "name": "my evc1",
234
            "uni_a": {
235
                "interface_id": "00:00:00:00:00:00:00:01:1",
236
                "tag": {"tag_type": 'vlan', "value": 80},
237
            },
238
            "uni_z": {
239
                "interface_id": "00:00:00:00:00:00:00:02:2",
240
                "tag": {"tag_type": 'vlan', "value": 1},
241
            },
242
            "circuit_scheduler": [
243
                {"frequency": "* * * * *", "action": "create"}
244
            ],
245
            "queue_id": 5,
246
        }
247
        # pylint: disable=protected-access
248 1
        evc_response = self.napp._evc_from_dict(payload)
249 1
        assert evc_response is not None
250 1
        assert evc_response.uni_a is not None
251 1
        assert evc_response.uni_z is not None
252 1
        assert evc_response.circuit_scheduler is not None
253 1
        assert evc_response.name is not None
254 1
        assert evc_response.queue_id is not None
255
256 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
257 1
    @patch("napps.kytos.mef_eline.models.evc.EVCBase._validate")
258 1
    @patch("kytos.core.Controller.get_interface_by_id")
259 1
    def test_evc_from_dict_paths(
260
        self, _get_interface_by_id_mock, _validate_mock, uni_from_dict_mock
261
    ):
262
        """
263
        Test the helper method that create an EVN from dict.
264
265
        Verify object creation with circuit data and schedule data.
266
        """
267
268 1
        _get_interface_by_id_mock.return_value = get_uni_mocked().interface
269 1
        _validate_mock.return_value = True
270 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
271 1
        payload = {
272
            "name": "my evc1",
273
            "uni_a": {
274
                "interface_id": "00:00:00:00:00:00:00:01:1",
275
                "tag": {"tag_type": 'vlan', "value": 80},
276
            },
277
            "uni_z": {
278
                "interface_id": "00:00:00:00:00:00:00:02:2",
279
                "tag": {"tag_type": 'vlan', "value": 1},
280
            },
281
            "current_path": [],
282
            "primary_path": [
283
                {
284
                    "endpoint_a": {
285
                        "interface_id": "00:00:00:00:00:00:00:01:1"
286
                    },
287
                    "endpoint_b": {
288
                        "interface_id": "00:00:00:00:00:00:00:02:2"
289
                    },
290
                }
291
            ],
292
            "backup_path": [],
293
        }
294
295
        # pylint: disable=protected-access
296 1
        evc_response = self.napp._evc_from_dict(payload)
297 1
        assert evc_response is not None
298 1
        assert evc_response.uni_a is not None
299 1
        assert evc_response.uni_z is not None
300 1
        assert evc_response.circuit_scheduler is not None
301 1
        assert evc_response.name is not None
302 1
        assert len(evc_response.current_path) == 0
303 1
        assert len(evc_response.backup_path) == 0
304 1
        assert len(evc_response.primary_path) == 1
305
306 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
307 1
    @patch("napps.kytos.mef_eline.models.evc.EVCBase._validate")
308 1
    @patch("kytos.core.Controller.get_interface_by_id")
309 1
    def test_evc_from_dict_links(
310
        self, _get_interface_by_id_mock, _validate_mock, uni_from_dict_mock
311
    ):
312
        """
313
        Test the helper method that create an EVN from dict.
314
315
        Verify object creation with circuit data and schedule data.
316
        """
317 1
        _get_interface_by_id_mock.return_value = get_uni_mocked().interface
318 1
        _validate_mock.return_value = True
319 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
320 1
        payload = {
321
            "name": "my evc1",
322
            "uni_a": {
323
                "interface_id": "00:00:00:00:00:00:00:01:1",
324
                "tag": {"tag_type": 'vlan', "value": 80},
325
            },
326
            "uni_z": {
327
                "interface_id": "00:00:00:00:00:00:00:02:2",
328
                "tag": {"tag_type": 'vlan', "value": 1},
329
            },
330
            "primary_links": [
331
                {
332
                    "endpoint_a": {
333
                        "interface_id": "00:00:00:00:00:00:00:01:1"
334
                    },
335
                    "endpoint_b": {
336
                        "interface_id": "00:00:00:00:00:00:00:02:2"
337
                    },
338
                    "metadata": {
339
                        "s_vlan": {
340
                            "tag_type": 'vlan',
341
                            "value": 100
342
                        }
343
                    },
344
                }
345
            ],
346
            "backup_links": [],
347
        }
348
349
        # pylint: disable=protected-access
350 1
        evc_response = self.napp._evc_from_dict(payload)
351 1
        assert evc_response is not None
352 1
        assert evc_response.uni_a is not None
353 1
        assert evc_response.uni_z is not None
354 1
        assert evc_response.circuit_scheduler is not None
355 1
        assert evc_response.name is not None
356 1
        assert len(evc_response.current_links_cache) == 0
357 1
        assert len(evc_response.backup_links) == 0
358 1
        assert len(evc_response.primary_links) == 1
359
360 1
    async def test_list_without_circuits(self):
361
        """Test if list circuits return 'no circuit stored.'."""
362 1
        circuits = {"circuits": {}}
363 1
        self.napp.mongo_controller.get_circuits.return_value = circuits
364 1
        url = f"{self.base_endpoint}/v2/evc/"
365 1
        response = await self.api_client.get(url)
366 1
        assert response.status_code == 200, response.data
367 1
        assert not response.json()
368
369 1
    async def test_list_no_circuits_stored(self):
370
        """Test if list circuits return all circuits stored."""
371 1
        circuits = {"circuits": {}}
372 1
        self.napp.mongo_controller.get_circuits.return_value = circuits
373
374 1
        url = f"{self.base_endpoint}/v2/evc/"
375 1
        response = await self.api_client.get(url)
376 1
        expected_result = circuits["circuits"]
377 1
        assert response.json() == expected_result
378
379 1 View Code Duplication
    async def test_list_with_circuits_stored(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
380
        """Test if list circuits return all circuits stored."""
381 1
        circuits = {
382
            'circuits':
383
            {"1": {"name": "circuit_1"}, "2": {"name": "circuit_2"}}
384
        }
385 1
        get_circuits = self.napp.mongo_controller.get_circuits
386 1
        get_circuits.return_value = circuits
387
388 1
        url = f"{self.base_endpoint}/v2/evc/"
389 1
        response = await self.api_client.get(url)
390 1
        expected_result = circuits["circuits"]
391 1
        get_circuits.assert_called_with(archived="false", metadata={})
392 1
        assert response.json() == expected_result
393
394 1 View Code Duplication
    async def test_list_with_archived_circuits_archived(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
395
        """Test if list circuits only archived circuits."""
396 1
        circuits = {
397
            'circuits':
398
            {
399
                "1": {"name": "circuit_1", "archived": True},
400
            }
401
        }
402 1
        get_circuits = self.napp.mongo_controller.get_circuits
403 1
        get_circuits.return_value = circuits
404
405 1
        url = f"{self.base_endpoint}/v2/evc/?archived=true&metadata.a=1"
406 1
        response = await self.api_client.get(url)
407 1
        get_circuits.assert_called_with(archived="true",
408
                                        metadata={"metadata.a": "1"})
409 1
        expected_result = {"1": circuits["circuits"]["1"]}
410 1
        assert response.json() == expected_result
411
412 1
    async def test_list_with_archived_circuits_all(self):
413
        """Test if list circuits return all circuits."""
414 1
        circuits = {
415
            'circuits': {
416
                "1": {"name": "circuit_1"},
417
                "2": {"name": "circuit_2", "archived": True},
418
            }
419
        }
420 1
        self.napp.mongo_controller.get_circuits.return_value = circuits
421
422 1
        url = f"{self.base_endpoint}/v2/evc/?archived=null"
423 1
        response = await self.api_client.get(url)
424 1
        expected_result = circuits["circuits"]
425 1
        assert response.json() == expected_result
426
427 1
    async def test_circuit_with_valid_id(self):
428
        """Test if get_circuit return the circuit attributes."""
429 1
        circuit = {"name": "circuit_1"}
430 1
        self.napp.mongo_controller.get_circuit.return_value = circuit
431
432 1
        url = f"{self.base_endpoint}/v2/evc/1"
433 1
        response = await self.api_client.get(url)
434 1
        expected_result = circuit
435 1
        assert response.json() == expected_result
436
437 1
    async def test_circuit_with_invalid_id(self):
438
        """Test if get_circuit return invalid circuit_id."""
439 1
        self.napp.mongo_controller.get_circuit.return_value = None
440 1
        url = f"{self.base_endpoint}/v2/evc/3"
441 1
        response = await self.api_client.get(url)
442
        expected_result = "circuit_id 3 not found"
443
        assert response.json()["description"] == expected_result
444
445 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
446 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
447 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
448 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
449 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
450 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
451 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
452 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
453 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
454 1
    async def test_create_a_circuit_case_1(
455
        self,
456
        validate_mock,
457
        evc_as_dict_mock,
458
        mongo_controller_upsert_mock,
459
        uni_from_dict_mock,
460
        sched_add_mock,
461
        evc_deploy_mock,
462
        mock_use_uni_tags,
463
        mock_tags_equal,
464
        mock_check_duplicate
465
    ):
466
        """Test create a new circuit."""
467
        # pylint: disable=too-many-locals
468 1
        self.napp.controller.loop = asyncio.get_running_loop()
469 1
        validate_mock.return_value = True
470 1
        mongo_controller_upsert_mock.return_value = True
471 1
        evc_deploy_mock.return_value = True
472 1
        mock_use_uni_tags.return_value = True
473 1
        mock_tags_equal.return_value = True
474 1
        mock_check_duplicate.return_value = True
475 1
        uni1 = create_autospec(UNI)
476 1
        uni2 = create_autospec(UNI)
477 1
        uni1.interface = create_autospec(Interface)
478 1
        uni2.interface = create_autospec(Interface)
479 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
480 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
481 1
        uni_from_dict_mock.side_effect = [uni1, uni2]
482 1
        evc_as_dict_mock.return_value = {}
483 1
        sched_add_mock.return_value = True
484 1
        self.napp.mongo_controller.get_circuits.return_value = {}
485
486 1
        url = f"{self.base_endpoint}/v2/evc/"
487 1
        payload = {
488
            "name": "my evc1",
489
            "frequency": "* * * * *",
490
            "uni_a": {
491
                "interface_id": "00:00:00:00:00:00:00:01:1",
492
                "tag": {"tag_type": 'vlan', "value": 80},
493
            },
494
            "uni_z": {
495
                "interface_id": "00:00:00:00:00:00:00:02:2",
496
                "tag": {"tag_type": 'vlan', "value": 1},
497
            },
498
            "dynamic_backup_path": True,
499
            "primary_constraints": {
500
                "spf_max_path_cost": 8,
501
                "mandatory_metrics": {
502
                    "ownership": "red"
503
                }
504
            },
505
            "secondary_constraints": {
506
                "spf_attribute": "priority",
507
                "mandatory_metrics": {
508
                    "ownership": "blue"
509
                }
510
            }
511
        }
512
513 1
        response = await self.api_client.post(url, json=payload)
514 1
        current_data = response.json()
515
516
        # verify expected result from request
517 1
        assert 201 == response.status_code
518 1
        assert "circuit_id" in current_data
519
520
        # verify uni called
521 1
        uni_from_dict_mock.called_twice()
522 1
        uni_from_dict_mock.assert_any_call(payload["uni_z"])
523 1
        uni_from_dict_mock.assert_any_call(payload["uni_a"])
524
525
        # verify validation called
526 1
        validate_mock.assert_called_once()
527 1
        validate_mock.assert_called_with(
528
            table_group={'evpl': 0, 'epl': 0},
529
            frequency="* * * * *",
530
            name="my evc1",
531
            uni_a=uni1,
532
            uni_z=uni2,
533
            dynamic_backup_path=True,
534
            primary_constraints=payload["primary_constraints"],
535
            secondary_constraints=payload["secondary_constraints"],
536
        )
537
        # verify save method is called
538 1
        mongo_controller_upsert_mock.assert_called_once()
539
540
        # verify evc as dict is called to save in the box
541 1
        evc_as_dict_mock.assert_called()
542
        # verify add circuit in sched
543 1
        sched_add_mock.assert_called_once()
544
545 1
    async def test_create_a_circuit_case_2(self):
546
        """Test create a new circuit trying to send request without a json."""
547 1
        self.napp.controller.loop = asyncio.get_running_loop()
548 1
        url = f"{self.base_endpoint}/v2/evc/"
549
550 1
        response = await self.api_client.post(url)
551
        current_data = response.json()
552
        assert 400 == response.status_code
553
        assert "Missing required request body" in current_data["description"]
554
555 1
    async def test_create_a_circuit_case_3(self):
556
        """Test create a new circuit trying to send request with an
557
        invalid json."""
558 1
        self.napp.controller.loop = asyncio.get_running_loop()
559 1
        url = f"{self.base_endpoint}/v2/evc/"
560
561 1
        response = await self.api_client.post(
562
            url,
563
            json="This is an {Invalid:} JSON",
564
        )
565
        current_data = response.json()
566
        assert 400 == response.status_code
567
        assert "This is an {Invalid:" in current_data["description"]
568
569 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
570 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
571 1
    async def test_create_a_circuit_case_4(
572
        self,
573
        mongo_controller_upsert_mock,
574
        uni_from_dict_mock
575
    ):
576
        """Test create a new circuit trying to send request with an
577
        invalid value."""
578 1
        self.napp.controller.loop = asyncio.get_running_loop()
579
        # pylint: disable=too-many-locals
580 1
        uni_from_dict_mock.side_effect = ValueError("Could not instantiate")
581 1
        mongo_controller_upsert_mock.return_value = True
582 1
        url = f"{self.base_endpoint}/v2/evc/"
583
584 1
        payload = {
585
            "name": "my evc1",
586
            "frequency": "* * * * *",
587
            "uni_a": {
588
                "interface_id": "00:00:00:00:00:00:00:01:76",
589
                "tag": {"tag_type": 'vlan', "value": 80},
590
            },
591
            "uni_z": {
592
                "interface_id": "00:00:00:00:00:00:00:02:2",
593
                "tag": {"tag_type": 'vlan', "value": 1},
594
            },
595
        }
596
597 1
        response = await self.api_client.post(url, json=payload)
598
        current_data = response.json()
599
        expected_data = "Error creating UNI: Invalid value"
600
        assert 400 == response.status_code
601
        assert current_data["description"] == expected_data
602
603
        payload["name"] = 1
604
        response = await self.api_client.post(url, json=payload)
605
        assert 400 == response.status_code, response.data
606
607 1 View Code Duplication
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
608 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
609 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
610 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
611 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
612 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
613 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
614 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
615 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
616 1
    async def test_create_a_circuit_case_5(
617
        self,
618
        validate_mock,
619
        evc_as_dict_mock,
620
        mongo_controller_upsert_mock,
621
        uni_from_dict_mock,
622
        sched_add_mock,
623
        evc_deploy_mock,
624
        mock_use_uni_tags,
625
        mock_tags_equal,
626
        mock_check_duplicate
627
    ):
628
        """Test create a new intra circuit with a disabled switch"""
629
        # pylint: disable=too-many-locals
630 1
        self.napp.controller.loop = asyncio.get_running_loop()
631 1
        validate_mock.return_value = True
632 1
        mongo_controller_upsert_mock.return_value = True
633 1
        evc_deploy_mock.return_value = True
634 1
        mock_use_uni_tags.return_value = True
635 1
        mock_tags_equal.return_value = True
636 1
        mock_check_duplicate.return_value = True
637 1
        uni1 = create_autospec(UNI)
638 1
        uni2 = create_autospec(UNI)
639 1
        uni1.interface = create_autospec(Interface)
640 1
        uni2.interface = create_autospec(Interface)
641 1
        switch = MagicMock()
642 1
        switch.status = EntityStatus.DISABLED
643 1
        switch.return_value = "00:00:00:00:00:00:00:01"
644 1
        uni1.interface.switch = switch
645 1
        uni2.interface.switch = switch
646 1
        uni_from_dict_mock.side_effect = [uni1, uni2]
647 1
        evc_as_dict_mock.return_value = {}
648 1
        sched_add_mock.return_value = True
649 1
        self.napp.mongo_controller.get_circuits.return_value = {}
650
651 1
        url = f"{self.base_endpoint}/v2/evc/"
652 1
        payload = {
653
            "name": "my evc1",
654
            "frequency": "* * * * *",
655
            "uni_a": {
656
                "interface_id": "00:00:00:00:00:00:00:01:1",
657
                "tag": {"tag_type": 'vlan', "value": 80},
658
            },
659
            "uni_z": {
660
                "interface_id": "00:00:00:00:00:00:00:01:2",
661
                "tag": {"tag_type": 'vlan', "value": 1},
662
            },
663
            "dynamic_backup_path": True,
664
            "primary_constraints": {
665
                "spf_max_path_cost": 8,
666
                "mandatory_metrics": {
667
                    "ownership": "red"
668
                }
669
            },
670
            "secondary_constraints": {
671
                "spf_attribute": "priority",
672
                "mandatory_metrics": {
673
                    "ownership": "blue"
674
                }
675
            }
676
        }
677
678 1
        response = await self.api_client.post(url, json=payload)
679 1
        current_data = response.json()
680
681
        # verify expected result from request
682 1
        assert 201 == response.status_code
683 1
        assert "circuit_id" in current_data
684
685
        # verify uni called
686 1
        uni_from_dict_mock.called_twice()
687 1
        uni_from_dict_mock.assert_any_call(payload["uni_z"])
688 1
        uni_from_dict_mock.assert_any_call(payload["uni_a"])
689
690
        # verify validation called
691 1
        validate_mock.assert_called_once()
692 1
        validate_mock.assert_called_with(
693
            table_group={'evpl': 0, 'epl': 0},
694
            frequency="* * * * *",
695
            name="my evc1",
696
            uni_a=uni1,
697
            uni_z=uni2,
698
            dynamic_backup_path=True,
699
            primary_constraints=payload["primary_constraints"],
700
            secondary_constraints=payload["secondary_constraints"],
701
        )
702
        # verify save method is called
703 1
        mongo_controller_upsert_mock.assert_called_once()
704
705
        # verify evc as dict is called to save in the box
706 1
        evc_as_dict_mock.assert_called()
707
        # verify add circuit in sched
708 1
        sched_add_mock.assert_called_once()
709
710 1 View Code Duplication
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
711 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
712 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
713 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
714 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
715 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
716 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
717 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
718 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
719 1
    async def test_create_a_circuit_case_6(
720
        self,
721
        validate_mock,
722
        evc_as_dict_mock,
723
        mongo_controller_upsert_mock,
724
        uni_from_dict_mock,
725
        sched_add_mock,
726
        evc_deploy_mock,
727
        mock_use_uni_tags,
728
        mock_tags_equal,
729
        mock_check_duplicate
730
    ):
731
        """Test create a new intra circuit with a disabled interface"""
732
        # pylint: disable=too-many-locals
733 1
        self.napp.controller.loop = asyncio.get_running_loop()
734 1
        validate_mock.return_value = True
735 1
        mongo_controller_upsert_mock.return_value = True
736 1
        evc_deploy_mock.return_value = True
737 1
        mock_use_uni_tags.return_value = True
738 1
        mock_tags_equal.return_value = True
739 1
        mock_check_duplicate.return_value = True
740 1
        uni1 = create_autospec(UNI)
741 1
        uni2 = create_autospec(UNI)
742 1
        uni1.interface = create_autospec(Interface)
743 1
        uni2.interface = create_autospec(Interface)
744 1
        switch = MagicMock()
745 1
        switch.status = EntityStatus.UP
746 1
        switch.return_value = "00:00:00:00:00:00:00:01"
747 1
        uni1.interface.switch = switch
748 1
        uni1.interface.status = EntityStatus.DISABLED
749 1
        uni2.interface.switch = switch
750 1
        uni_from_dict_mock.side_effect = [uni1, uni2]
751 1
        evc_as_dict_mock.return_value = {}
752 1
        sched_add_mock.return_value = True
753 1
        self.napp.mongo_controller.get_circuits.return_value = {}
754
755 1
        url = f"{self.base_endpoint}/v2/evc/"
756 1
        payload = {
757
            "name": "my evc1",
758
            "frequency": "* * * * *",
759
            "uni_a": {
760
                "interface_id": "00:00:00:00:00:00:00:01:1",
761
                "tag": {"tag_type": 'vlan', "value": 80},
762
            },
763
            "uni_z": {
764
                "interface_id": "00:00:00:00:00:00:00:01:2",
765
                "tag": {"tag_type": 'vlan', "value": 1},
766
            },
767
            "dynamic_backup_path": True,
768
            "primary_constraints": {
769
                "spf_max_path_cost": 8,
770
                "mandatory_metrics": {
771
                    "ownership": "red"
772
                }
773
            },
774
            "secondary_constraints": {
775
                "spf_attribute": "priority",
776
                "mandatory_metrics": {
777
                    "ownership": "blue"
778
                }
779
            }
780
        }
781
782 1
        response = await self.api_client.post(url, json=payload)
783 1
        current_data = response.json()
784
785
        # verify expected result from request
786 1
        assert 201 == response.status_code
787 1
        assert "circuit_id" in current_data
788
789
        # verify uni called
790 1
        uni_from_dict_mock.called_twice()
791 1
        uni_from_dict_mock.assert_any_call(payload["uni_z"])
792 1
        uni_from_dict_mock.assert_any_call(payload["uni_a"])
793
794
        # verify validation called
795 1
        validate_mock.assert_called_once()
796 1
        validate_mock.assert_called_with(
797
            table_group={'evpl': 0, 'epl': 0},
798
            frequency="* * * * *",
799
            name="my evc1",
800
            uni_a=uni1,
801
            uni_z=uni2,
802
            dynamic_backup_path=True,
803
            primary_constraints=payload["primary_constraints"],
804
            secondary_constraints=payload["secondary_constraints"],
805
        )
806
        # verify save method is called
807 1
        mongo_controller_upsert_mock.assert_called_once()
808
809
        # verify evc as dict is called to save in the box
810 1
        evc_as_dict_mock.assert_called()
811
        # verify add circuit in sched
812 1
        sched_add_mock.assert_called_once()
813
814 1
    async def test_create_a_circuit_invalid_queue_id(self):
815
        """Test create a new circuit with invalid queue_id."""
816 1
        self.napp.controller.loop = asyncio.get_running_loop()
817 1
        url = f"{self.base_endpoint}/v2/evc/"
818
819 1
        payload = {
820
            "name": "my evc1",
821
            "queue_id": 8,
822
            "uni_a": {
823
                "interface_id": "00:00:00:00:00:00:00:01:76",
824
                "tag": {"tag_type": 'vlan', "value": 80},
825
            },
826
            "uni_z": {
827
                "interface_id": "00:00:00:00:00:00:00:02:2",
828
                "tag": {"tag_type": 'vlan', "value": 1},
829
            },
830
        }
831 1
        response = await self.api_client.post(url, json=payload)
832
        current_data = response.json()
833
        expected_data = "8 is greater than the maximum of 7"
834
835
        assert response.status_code == 400
836
        assert expected_data in current_data["description"]
837
838 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
839 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
840 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
841 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
842 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
843 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
844 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
845 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
846 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
847 1
    async def test_create_circuit_already_enabled(
848
        self,
849
        evc_as_dict_mock,
850
        validate_mock,
851
        mongo_controller_upsert_mock,
852
        uni_from_dict_mock,
853
        sched_add_mock,
854
        evc_deploy_mock,
855
        mock_use_uni_tags,
856
        mock_tags_equal,
857
        mock_check_duplicate
858
    ):
859
        """Test create an already created circuit."""
860
        # pylint: disable=too-many-locals
861 1
        self.napp.controller.loop = asyncio.get_running_loop()
862 1
        validate_mock.return_value = True
863 1
        mongo_controller_upsert_mock.return_value = True
864 1
        sched_add_mock.return_value = True
865 1
        evc_deploy_mock.return_value = True
866 1
        mock_tags_equal.return_value = True
867 1
        mock_check_duplicate.return_value = True
868 1
        mock_use_uni_tags.side_effect = [
869
            None, KytosTagError("The EVC already exists.")
870
        ]
871 1
        uni1 = create_autospec(UNI)
872 1
        uni2 = create_autospec(UNI)
873 1
        uni1.interface = create_autospec(Interface)
874 1
        uni2.interface = create_autospec(Interface)
875 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
876 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
877 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
878
879 1
        payload = {
880
            "name": "my evc1",
881
            "uni_a": {
882
                "interface_id": "00:00:00:00:00:00:00:01:1",
883
                "tag": {"tag_type": 'vlan', "value": 80},
884
            },
885
            "uni_z": {
886
                "interface_id": "00:00:00:00:00:00:00:02:2",
887
                "tag": {"tag_type": 'vlan', "value": 1},
888
            },
889
            "dynamic_backup_path": True,
890
        }
891
892 1
        evc_as_dict_mock.return_value = payload
893 1
        response = await self.api_client.post(
894
            f"{self.base_endpoint}/v2/evc/",
895
            json=payload
896
        )
897 1
        assert 201 == response.status_code
898
899 1
        response = await self.api_client.post(
900
            f"{self.base_endpoint}/v2/evc/",
901
            json=payload
902
        )
903
        current_data = response.json()
904
        expected_data = "The EVC already exists."
905
        assert current_data["description"] == expected_data
906
        assert 400 == response.status_code
907
908 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
909 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
910 1
    async def test_create_circuit_case_5(
911
        self,
912
        uni_from_dict_mock,
913
        mock_tags_equal
914
    ):
915
        """Test when neither primary path nor dynamic_backup_path is set."""
916 1
        self.napp.controller.loop = asyncio.get_running_loop()
917 1
        mock_tags_equal.return_value = True
918 1
        url = f"{self.base_endpoint}/v2/evc/"
919 1
        uni1 = create_autospec(UNI)
920 1
        uni2 = create_autospec(UNI)
921 1
        uni1.interface = create_autospec(Interface)
922 1
        uni2.interface = create_autospec(Interface)
923 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
924 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
925 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
926
927 1
        payload = {
928
            "name": "my evc1",
929
            "frequency": "* * * * *",
930
            "uni_a": {
931
                "interface_id": "00:00:00:00:00:00:00:01:1",
932
                "tag": {"tag_type": 'vlan', "value": 80},
933
            },
934
            "uni_z": {
935
                "interface_id": "00:00:00:00:00:00:00:02:2",
936
                "tag": {"tag_type": 'vlan', "value": 1},
937
            },
938
        }
939
940 1
        response = await self.api_client.post(url, json=payload)
941
        current_data = response.json()
942
        expected_data = "The EVC must have a primary path "
943
        expected_data += "or allow dynamic paths."
944
        assert 400 == response.status_code, response.data
945
        assert current_data["description"] == expected_data
946
947 1
    @patch("napps.kytos.mef_eline.main.Main._evc_from_dict")
948 1
    async def test_create_circuit_case_6(self, mock_evc):
949
        """Test create_circuit with KytosTagError"""
950 1
        self.napp.controller.loop = asyncio.get_running_loop()
951 1
        url = f"{self.base_endpoint}/v2/evc/"
952 1
        mock_evc.side_effect = KytosTagError("")
953 1
        payload = {
954
            "name": "my evc1",
955
            "uni_a": {
956
                "interface_id": "00:00:00:00:00:00:00:01:1",
957
            },
958
            "uni_z": {
959
                "interface_id": "00:00:00:00:00:00:00:02:2",
960
            },
961
        }
962 1
        response = await self.api_client.post(url, json=payload)
963
        assert response.status_code == 400, response.data
964
965 1
    async def test_redeploy_evc(self):
966
        """Test endpoint to redeploy an EVC."""
967 1
        evc1 = MagicMock()
968 1
        evc1.is_enabled.return_value = True
969 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
970 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
971 1
        response = await self.api_client.patch(url)
972 1
        evc1.remove_failover_flows.assert_called()
973 1
        evc1.remove_current_flows.assert_called_with(
974
            sync=False, return_path=True
975
        )
976 1
        assert response.status_code == 202, response.data
977
978 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
979 1
        url = url + "?try_avoid_same_s_vlan=false"
980 1
        response = await self.api_client.patch(url)
981 1
        evc1.remove_current_flows.assert_called_with(
982
            sync=False, return_path=False
983
        )
984
985 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
986 1
        url = url + "?try_avoid_same_s_vlan=True"
987 1
        response = await self.api_client.patch(url)
988 1
        evc1.remove_current_flows.assert_called_with(
989
            sync=False, return_path=True
990
        )
991
992 1
    async def test_redeploy_evc_disabled(self):
993
        """Test endpoint to redeploy an EVC."""
994 1
        evc1 = MagicMock()
995 1
        evc1.is_enabled.return_value = False
996 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
997 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
998 1
        response = await self.api_client.patch(url)
999 1
        evc1.remove_failover_flows.assert_not_called()
1000 1
        evc1.remove_current_flows.assert_not_called()
1001 1
        assert response.status_code == 409, response.data
1002
1003 1
    async def test_redeploy_evc_deleted(self):
1004
        """Test endpoint to redeploy an EVC."""
1005 1
        evc1 = MagicMock()
1006 1
        evc1.is_enabled.return_value = True
1007 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
1008 1
        url = f"{self.base_endpoint}/v2/evc/3/redeploy"
1009 1
        response = await self.api_client.patch(url)
1010
        assert response.status_code == 404, response.data
1011
1012 1
    async def test_list_schedules__no_data_stored(self):
1013
        """Test if list circuits return all circuits stored."""
1014 1
        self.napp.mongo_controller.get_circuits.return_value = {"circuits": {}}
1015
1016 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
1017
1018 1
        response = await self.api_client.get(url)
1019 1
        assert response.status_code == 200
1020 1
        assert not response.json()
1021
1022 1
    def _add_mongodb_schedule_data(self, data_mock):
1023
        """Add schedule data to mongodb mock object."""
1024 1
        circuits = {"circuits": {}}
1025 1
        payload_1 = {
1026
            "id": "aa:aa:aa",
1027
            "name": "my evc1",
1028
            "uni_a": {
1029
                "interface_id": "00:00:00:00:00:00:00:01:1",
1030
                "tag": {"tag_type": 'vlan', "value": 80},
1031
            },
1032
            "uni_z": {
1033
                "interface_id": "00:00:00:00:00:00:00:02:2",
1034
                "tag": {"tag_type": 'vlan', "value": 1},
1035
            },
1036
            "circuit_scheduler": [
1037
                {"id": "1", "frequency": "* * * * *", "action": "create"},
1038
                {"id": "2", "frequency": "1 * * * *", "action": "remove"},
1039
            ],
1040
        }
1041 1
        circuits["circuits"].update({"aa:aa:aa": payload_1})
1042 1
        payload_2 = {
1043
            "id": "bb:bb:bb",
1044
            "name": "my second evc2",
1045
            "uni_a": {
1046
                "interface_id": "00:00:00:00:00:00:00:01:2",
1047
                "tag": {"tag_type": 'vlan', "value": 90},
1048
            },
1049
            "uni_z": {
1050
                "interface_id": "00:00:00:00:00:00:00:03:2",
1051
                "tag": {"tag_type": 'vlan', "value": 100},
1052
            },
1053
            "circuit_scheduler": [
1054
                {"id": "3", "frequency": "1 * * * *", "action": "create"},
1055
                {"id": "4", "frequency": "2 * * * *", "action": "remove"},
1056
            ],
1057
        }
1058 1
        circuits["circuits"].update({"bb:bb:bb": payload_2})
1059 1
        payload_3 = {
1060
            "id": "cc:cc:cc",
1061
            "name": "my third evc3",
1062
            "uni_a": {
1063
                "interface_id": "00:00:00:00:00:00:00:03:1",
1064
                "tag": {"tag_type": 'vlan', "value": 90},
1065
            },
1066
            "uni_z": {
1067
                "interface_id": "00:00:00:00:00:00:00:04:2",
1068
                "tag": {"tag_type": 'vlan', "value": 100},
1069
            },
1070
        }
1071 1
        circuits["circuits"].update({"cc:cc:cc": payload_3})
1072
        # Add one circuit to the mongodb.
1073 1
        data_mock.return_value = circuits
1074
1075 1
    async def test_list_schedules_from_mongodb(self):
1076
        """Test if list circuits return specific circuits stored."""
1077 1
        self._add_mongodb_schedule_data(
1078
            self.napp.mongo_controller.get_circuits
1079
        )
1080
1081 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
1082
1083
        # Call URL
1084 1
        response = await self.api_client.get(url)
1085
        # Expected JSON data from response
1086 1
        expected = [
1087
            {
1088
                "circuit_id": "aa:aa:aa",
1089
                "schedule": {
1090
                    "action": "create",
1091
                    "frequency": "* * * * *",
1092
                    "id": "1",
1093
                },
1094
                "schedule_id": "1",
1095
            },
1096
            {
1097
                "circuit_id": "aa:aa:aa",
1098
                "schedule": {
1099
                    "action": "remove",
1100
                    "frequency": "1 * * * *",
1101
                    "id": "2",
1102
                },
1103
                "schedule_id": "2",
1104
            },
1105
            {
1106
                "circuit_id": "bb:bb:bb",
1107
                "schedule": {
1108
                    "action": "create",
1109
                    "frequency": "1 * * * *",
1110
                    "id": "3",
1111
                },
1112
                "schedule_id": "3",
1113
            },
1114
            {
1115
                "circuit_id": "bb:bb:bb",
1116
                "schedule": {
1117
                    "action": "remove",
1118
                    "frequency": "2 * * * *",
1119
                    "id": "4",
1120
                },
1121
                "schedule_id": "4",
1122
            },
1123
        ]
1124
1125 1
        assert response.status_code == 200
1126 1
        assert expected == response.json()
1127
1128 1
    async def test_get_specific_schedule_from_mongodb(self):
1129
        """Test get schedules from a circuit."""
1130 1
        self._add_mongodb_schedule_data(
1131
            self.napp.mongo_controller.get_circuits
1132
        )
1133
1134 1
        requested_circuit_id = "bb:bb:bb"
1135 1
        evc = self.napp.mongo_controller.get_circuits()
1136 1
        evc = evc["circuits"][requested_circuit_id]
1137 1
        self.napp.mongo_controller.get_circuit.return_value = evc
1138 1
        url = f"{self.base_endpoint}/v2/evc/{requested_circuit_id}"
1139
1140
        # Call URL
1141 1
        response = await self.api_client.get(url)
1142
1143
        # Expected JSON data from response
1144 1
        expected = [
1145
            {"action": "create", "frequency": "1 * * * *", "id": "3"},
1146
            {"action": "remove", "frequency": "2 * * * *", "id": "4"},
1147
        ]
1148
1149 1
        assert response.status_code == 200
1150 1
        assert expected == response.json()["circuit_scheduler"]
1151
1152 1
    async def test_get_specific_schedules_from_mongodb_not_found(self):
1153
        """Test get specific schedule ID that does not exist."""
1154 1
        requested_id = "blah"
1155 1
        self.napp.mongo_controller.get_circuit.return_value = None
1156 1
        url = f"{self.base_endpoint}/v2/evc/{requested_id}"
1157
1158
        # Call URL
1159 1
        response = await self.api_client.get(url)
1160
1161
        expected = "circuit_id blah not found"
1162
        # Assert response not found
1163
        assert response.status_code == 404
1164
        assert expected == response.json()["description"]
1165
1166 1
    def _uni_from_dict_side_effect(self, uni_dict):
1167 1
        interface_id = uni_dict.get("interface_id")
1168 1
        tag_dict = uni_dict.get("tag")
1169 1
        interface = Interface(interface_id, "0", MagicMock(id="1"))
1170 1
        return UNI(interface, tag_dict)
1171
1172 1
    @patch("apscheduler.schedulers.background.BackgroundScheduler.add_job")
1173 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1174 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1175 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1176 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1177 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1178 1
    async def test_create_schedule(
1179
        self,
1180
        validate_mock,
1181
        evc_as_dict_mock,
1182
        mongo_controller_upsert_mock,
1183
        uni_from_dict_mock,
1184
        sched_add_mock,
1185
        scheduler_add_job_mock
1186
    ):
1187
        """Test create a circuit schedule."""
1188 1
        self.napp.controller.loop = asyncio.get_running_loop()
1189 1
        validate_mock.return_value = True
1190 1
        mongo_controller_upsert_mock.return_value = True
1191 1
        uni_from_dict_mock.side_effect = self._uni_from_dict_side_effect
1192 1
        evc_as_dict_mock.return_value = {}
1193 1
        sched_add_mock.return_value = True
1194
1195 1
        self._add_mongodb_schedule_data(
1196
            self.napp.mongo_controller.get_circuits
1197
        )
1198
1199 1
        requested_id = "bb:bb:bb"
1200 1
        url = f"{self.base_endpoint}/v2/evc/schedule/"
1201
1202 1
        payload = {
1203
            "circuit_id": requested_id,
1204
            "schedule": {"frequency": "1 * * * *", "action": "create"},
1205
            "metadata": {"metadata1": "test_data"},
1206
        }
1207
1208
        # Call URL
1209 1
        response = await self.api_client.post(url, json=payload)
1210 1
        response_json = response.json()
1211
1212 1
        assert response.status_code == 201
1213 1
        scheduler_add_job_mock.assert_called_once()
1214 1
        mongo_controller_upsert_mock.assert_called_once()
1215 1
        assert payload["schedule"]["frequency"] == response_json["frequency"]
1216 1
        assert payload["schedule"]["action"] == response_json["action"]
1217 1
        assert response_json["id"] is not None
1218
1219
        # Case 2: there is no schedule
1220 1
        payload = {
1221
              "circuit_id": "cc:cc:cc",
1222
              "schedule": {
1223
                "frequency": "1 * * * *",
1224
                "action": "create"
1225
              }
1226
            }
1227 1
        response = await self.api_client.post(url, json=payload)
1228 1
        assert response.status_code == 201
1229
1230 1
    async def test_create_schedule_invalid_request(self):
1231
        """Test create schedule API with invalid request."""
1232 1
        self.napp.controller.loop = asyncio.get_running_loop()
1233 1
        evc1 = MagicMock()
1234 1
        self.napp.circuits = {'bb:bb:bb': evc1}
1235 1
        url = f'{self.base_endpoint}/v2/evc/schedule/'
1236
1237
        # case 1: empty post
1238 1
        response = await self.api_client.post(url, json={})
1239
        assert response.status_code == 400
1240
1241
        # case 2: not a dictionary
1242
        payload = []
1243
        response = await self.api_client.post(url, json=payload)
1244
        assert response.status_code == 400
1245
1246
        # case 3: missing circuit id
1247
        payload = {
1248
            "schedule": {
1249
                "frequency": "1 * * * *",
1250
                "action": "create"
1251
            }
1252
        }
1253
        response = await self.api_client.post(url, json=payload)
1254
        assert response.status_code == 400
1255
1256
        # case 4: missing schedule
1257
        payload = {
1258
            "circuit_id": "bb:bb:bb"
1259
        }
1260
        response = await self.api_client.post(url, json=payload)
1261
        assert response.status_code == 400
1262
1263
        # case 5: invalid circuit
1264
        payload = {
1265
            "circuit_id": "xx:xx:xx",
1266
            "schedule": {
1267
                "frequency": "1 * * * *",
1268
                "action": "create"
1269
            }
1270
        }
1271
        response = await self.api_client.post(url, json=payload)
1272
        assert response.status_code == 404
1273
1274
        # case 6: invalid json
1275
        response = await self.api_client.post(url, json="test")
1276
        assert response.status_code == 400
1277
1278 1
    @patch('apscheduler.schedulers.background.BackgroundScheduler.remove_job')
1279 1
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1280 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1281 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1282 1
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1283 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1284 1
    async def test_update_schedule(
1285
        self,
1286
        validate_mock,
1287
        evc_as_dict_mock,
1288
        mongo_controller_upsert_mock,
1289
        uni_from_dict_mock,
1290
        sched_add_mock,
1291
        scheduler_remove_job_mock
1292
    ):
1293
        """Test create a circuit schedule."""
1294 1
        self.napp.controller.loop = asyncio.get_running_loop()
1295 1
        mongo_payload_1 = {
1296
            "circuits": {
1297
                "aa:aa:aa": {
1298
                    "id": "aa:aa:aa",
1299
                    "name": "my evc1",
1300
                    "uni_a": {
1301
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1302
                        "tag": {"tag_type": 'vlan', "value": 80},
1303
                    },
1304
                    "uni_z": {
1305
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1306
                        "tag": {"tag_type": 'vlan', "value": 1},
1307
                    },
1308
                    "circuit_scheduler": [
1309
                        {
1310
                            "id": "1",
1311
                            "frequency": "* * * * *",
1312
                            "action": "create"
1313
                        }
1314
                    ],
1315
                }
1316
            }
1317
        }
1318
1319 1
        validate_mock.return_value = True
1320 1
        mongo_controller_upsert_mock.return_value = True
1321 1
        sched_add_mock.return_value = True
1322 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1323 1
        evc_as_dict_mock.return_value = {}
1324 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1325 1
        scheduler_remove_job_mock.return_value = True
1326
1327 1
        requested_schedule_id = "1"
1328 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1329
1330 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1331
1332
        # Call URL
1333 1
        response = await self.api_client.patch(url, json=payload)
1334 1
        response_json = response.json()
1335
1336 1
        assert response.status_code == 200
1337 1
        scheduler_remove_job_mock.assert_called_once()
1338 1
        mongo_controller_upsert_mock.assert_called_once()
1339 1
        assert payload["frequency"] == response_json["frequency"]
1340 1
        assert payload["action"] == response_json["action"]
1341 1
        assert response_json["id"] is not None
1342
1343 1
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1344 1
    async def test_update_no_schedule(
1345
        self, find_evc_by_schedule_id_mock
1346
    ):
1347
        """Test update a circuit schedule."""
1348 1
        self.napp.controller.loop = asyncio.get_running_loop()
1349 1
        url = f"{self.base_endpoint}/v2/evc/schedule/1"
1350 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1351
1352 1
        find_evc_by_schedule_id_mock.return_value = None, None
1353
1354 1
        response = await self.api_client.patch(url, json=payload)
1355
        assert response.status_code == 404
1356
1357 1
    @patch("apscheduler.schedulers.background.BackgroundScheduler.remove_job")
1358 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1359 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1360 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1361 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1362 1
    async def test_delete_schedule(self, *args):
1363
        """Test create a circuit schedule."""
1364 1
        (
1365
            validate_mock,
1366
            evc_as_dict_mock,
1367
            mongo_controller_upsert_mock,
1368
            uni_from_dict_mock,
1369
            scheduler_remove_job_mock,
1370
        ) = args
1371
1372 1
        mongo_payload_1 = {
1373
            "circuits": {
1374
                "2": {
1375
                    "id": "2",
1376
                    "name": "my evc1",
1377
                    "uni_a": {
1378
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1379
                        "tag": {"tag_type": 'vlan', "value": 80},
1380
                    },
1381
                    "uni_z": {
1382
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1383
                        "tag": {"tag_type": 'vlan', "value": 1},
1384
                    },
1385
                    "circuit_scheduler": [
1386
                        {
1387
                            "id": "1",
1388
                            "frequency": "* * * * *",
1389
                            "action": "create"
1390
                        }
1391
                    ],
1392
                }
1393
            }
1394
        }
1395 1
        validate_mock.return_value = True
1396 1
        mongo_controller_upsert_mock.return_value = True
1397 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1398 1
        evc_as_dict_mock.return_value = {}
1399 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1400 1
        scheduler_remove_job_mock.return_value = True
1401
1402 1
        requested_schedule_id = "1"
1403 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1404
1405
        # Call URL
1406 1
        response = await self.api_client.delete(url)
1407
1408 1
        assert response.status_code == 200
1409 1
        scheduler_remove_job_mock.assert_called_once()
1410 1
        mongo_controller_upsert_mock.assert_called_once()
1411 1
        assert "Schedule removed" in f"{response.json()}"
1412
1413 1
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1414 1
    async def test_delete_schedule_not_found(self, mock_find_evc_by_sched):
1415
        """Test delete a circuit schedule - unexisting."""
1416 1
        mock_find_evc_by_sched.return_value = (None, False)
1417 1
        url = f'{self.base_endpoint}/v2/evc/schedule/1'
1418 1
        response = await self.api_client.delete(url)
1419
        assert response.status_code == 404
1420
1421 1
    def test_get_evcs_by_svc_level(self) -> None:
1422
        """Test get_evcs_by_svc_level."""
1423 1
        levels = [1, 2, 4, 2, 7]
1424 1
        evcs = {i: MagicMock(service_level=v, creation_time=1)
1425
                for i, v in enumerate(levels)}
1426 1
        self.napp.circuits = evcs
1427 1
        expected_levels = sorted(levels, reverse=True)
1428 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1429 1
        assert evcs_by_level
1430
1431 1
        for evc, exp_level in zip(evcs_by_level, expected_levels):
1432 1
            assert evc.service_level == exp_level
1433
1434 1
        evcs = {i: MagicMock(service_level=1, creation_time=i)
1435
                for i in reversed(range(2))}
1436 1
        self.napp.circuits = evcs
1437 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1438 1
        for i in range(2):
1439 1
            assert evcs_by_level[i].creation_time == i
1440
1441 1
        self.napp.circuits[1].is_enabled = lambda: False
1442 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1443 1
        assert len(evcs_by_level) == 1
1444
1445 1
        self.napp.circuits[1].is_enabled = lambda: False
1446 1
        evcs_by_level = self.napp.get_evcs_by_svc_level(enable_filter=False)
1447 1
        assert len(evcs_by_level) == 2
1448
1449 1
    async def test_get_circuit_not_found(self):
1450
        """Test /v2/evc/<circuit_id> 404."""
1451 1
        self.napp.mongo_controller.get_circuit.return_value = None
1452 1
        url = f'{self.base_endpoint}/v2/evc/1234'
1453 1
        response = await self.api_client.get(url)
1454
        assert response.status_code == 404
1455
1456 1
    @patch('httpx.post')
1457 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1458 1
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1459 1
    @patch('napps.kytos.mef_eline.controllers.ELineController.update_evc')
1460 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1461 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1462 1
    @patch('kytos.core.Controller.get_interface_by_id')
1463 1
    @patch('napps.kytos.mef_eline.models.path.Path.is_valid')
1464 1
    @patch('napps.kytos.mef_eline.models.evc.EVCDeploy.deploy')
1465 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1466 1
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1467 1
    async def test_update_circuit(
1468
        self,
1469
        evc_as_dict_mock,
1470
        uni_from_dict_mock,
1471
        evc_deploy,
1472
        _is_valid_mock,
1473
        interface_by_id_mock,
1474
        _mock_validate,
1475
        _mongo_controller_upsert_mock,
1476
        _mongo_controller_update_mock,
1477
        _sched_add_mock,
1478
        mock_use_uni_tags,
1479
        httpx_mock
1480
    ):
1481
        """Test update a circuit circuit."""
1482 1
        self.napp.controller.loop = asyncio.get_running_loop()
1483 1
        mock_use_uni_tags.return_value = True
1484 1
        evc_deploy.return_value = True
1485 1
        interface_by_id_mock.return_value = get_uni_mocked().interface
1486 1
        unis = [
1487
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:01"),
1488
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:02"),
1489
        ]
1490 1
        uni_from_dict_mock.side_effect = 2 * unis
1491
1492 1
        response = MagicMock()
1493 1
        response.status_code = 201
1494 1
        httpx_mock.return_value = response
1495
1496 1
        payloads = [
1497
            {
1498
                "name": "my evc1",
1499
                "uni_a": {
1500
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1501
                    "tag": {"tag_type": 'vlan', "value": 80},
1502
                },
1503
                "uni_z": {
1504
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1505
                    "tag": {"tag_type": 'vlan', "value": 1},
1506
                },
1507
                "dynamic_backup_path": True,
1508
            },
1509
            {
1510
                "primary_path": [
1511
                    {
1512
                        "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1513
                        "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1514
                    }
1515
                ]
1516
            },
1517
            {
1518
                "sb_priority": 3
1519
            },
1520
            {
1521
                # It works only with 'enabled' and not with 'enable'
1522
                "enabled": True
1523
            },
1524
            {
1525
                "sb_priority": 100
1526
            }
1527
        ]
1528
1529 1
        evc_as_dict_mock.return_value = payloads[0]
1530 1
        response = await self.api_client.post(
1531
            f"{self.base_endpoint}/v2/evc/",
1532
            json=payloads[0],
1533
        )
1534 1
        assert 201 == response.status_code
1535
1536 1
        evc_deploy.reset_mock()
1537 1
        evc_as_dict_mock.return_value = payloads[1]
1538 1
        current_data = response.json()
1539 1
        circuit_id = current_data["circuit_id"]
1540 1
        response = await self.api_client.patch(
1541
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1542
            json=payloads[1],
1543
        )
1544
        # evc_deploy.assert_called_once()
1545 1
        assert 200 == response.status_code
1546
1547 1
        evc_deploy.reset_mock()
1548 1
        evc_as_dict_mock.return_value = payloads[2]
1549 1
        response = await self.api_client.patch(
1550
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1551
            json=payloads[2],
1552
        )
1553 1
        evc_deploy.assert_not_called()
1554 1
        assert 200 == response.status_code
1555
1556 1
        evc_deploy.reset_mock()
1557 1
        evc_as_dict_mock.return_value = payloads[3]
1558 1
        response = await self.api_client.patch(
1559
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1560
            json=payloads[3],
1561
        )
1562 1
        evc_deploy.assert_called_once()
1563 1
        assert 200 == response.status_code
1564
1565 1
        evc_deploy.reset_mock()
1566 1
        response = await self.api_client.patch(
1567
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1568
            content=b'{"priority":5,}',
1569
            headers={"Content-Type": "application/json"}
1570
        )
1571
        evc_deploy.assert_not_called()
1572
        assert 400 == response.status_code
1573
1574
        response = await self.api_client.patch(
1575
            f"{self.base_endpoint}/v2/evc/1234",
1576
            json=payloads[1],
1577
        )
1578
        current_data = response.json()
1579
        expected_data = "circuit_id 1234 not found"
1580
        assert current_data["description"] == expected_data
1581
        assert 404 == response.status_code
1582
1583
        self.napp.circuits[circuit_id]._active = False
1584
        evc_deploy.reset_mock()
1585
        response = await self.api_client.patch(
1586
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1587
            json=payloads[4]
1588
        )
1589 1
        assert 200 == response.status_code
1590 1
        evc_deploy.assert_called_once()
1591
1592 1 View Code Duplication
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1593 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1594 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1595 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1596 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1597 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1598 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1599 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1600 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1601 1
    async def test_update_circuit_invalid_json(
1602
        self,
1603
        evc_as_dict_mock,
1604
        validate_mock,
1605
        mongo_controller_upsert_mock,
1606
        uni_from_dict_mock,
1607
        sched_add_mock,
1608
        evc_deploy_mock,
1609
        mock_use_uni_tags,
1610
        mock_tags_equal,
1611
        mock_check_duplicate
1612
    ):
1613
        """Test update a circuit circuit."""
1614 1
        self.napp.controller.loop = asyncio.get_running_loop()
1615 1
        validate_mock.return_value = True
1616 1
        mongo_controller_upsert_mock.return_value = True
1617 1
        sched_add_mock.return_value = True
1618 1
        evc_deploy_mock.return_value = True
1619 1
        mock_use_uni_tags.return_value = True
1620 1
        mock_tags_equal.return_value = True
1621 1
        mock_check_duplicate.return_value = True
1622 1
        uni1 = create_autospec(UNI)
1623 1
        uni2 = create_autospec(UNI)
1624 1
        uni1.interface = create_autospec(Interface)
1625 1
        uni2.interface = create_autospec(Interface)
1626 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1627 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1628 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1629
1630 1
        payload1 = {
1631
            "name": "my evc1",
1632
            "uni_a": {
1633
                "interface_id": "00:00:00:00:00:00:00:01:1",
1634
                "tag": {"tag_type": 'vlan', "value": 80},
1635
            },
1636
            "uni_z": {
1637
                "interface_id": "00:00:00:00:00:00:00:02:2",
1638
                "tag": {"tag_type": 'vlan', "value": 1},
1639
            },
1640
            "dynamic_backup_path": True,
1641
        }
1642
1643 1
        payload2 = {
1644
            "dynamic_backup_path": False,
1645
        }
1646
1647 1
        evc_as_dict_mock.return_value = payload1
1648 1
        response = await self.api_client.post(
1649
            f"{self.base_endpoint}/v2/evc/",
1650
            json=payload1
1651
        )
1652 1
        assert 201 == response.status_code
1653
1654 1
        evc_as_dict_mock.return_value = payload2
1655 1
        current_data = response.json()
1656 1
        circuit_id = current_data["circuit_id"]
1657 1
        response = await self.api_client.patch(
1658
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1659
            json=payload2
1660
        )
1661
        current_data = response.json()
1662
        assert 400 == response.status_code
1663
        assert "must have a primary path or" in current_data["description"]
1664
1665 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
1666 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1667 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1668 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1669 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1670 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1671 1
    @patch("napps.kytos.mef_eline.main.Main._link_from_dict")
1672 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1673 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1674 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1675 1
    @patch("napps.kytos.mef_eline.models.path.Path.is_valid")
1676 1
    async def test_update_circuit_invalid_path(
1677
        self,
1678
        is_valid_mock,
1679
        evc_as_dict_mock,
1680
        validate_mock,
1681
        mongo_controller_upsert_mock,
1682
        link_from_dict_mock,
1683
        uni_from_dict_mock,
1684
        sched_add_mock,
1685
        evc_deploy_mock,
1686
        mock_use_uni_tags,
1687
        mock_tags_equal,
1688
        mock_check_duplicate
1689
    ):
1690
        """Test update a circuit circuit."""
1691 1
        self.napp.controller.loop = asyncio.get_running_loop()
1692 1
        is_valid_mock.side_effect = InvalidPath("error")
1693 1
        validate_mock.return_value = True
1694 1
        mongo_controller_upsert_mock.return_value = True
1695 1
        sched_add_mock.return_value = True
1696 1
        evc_deploy_mock.return_value = True
1697 1
        mock_use_uni_tags.return_value = True
1698 1
        link_from_dict_mock.return_value = 1
1699 1
        mock_tags_equal.return_value = True
1700 1
        mock_check_duplicate.return_value = True
1701 1
        uni1 = create_autospec(UNI)
1702 1
        uni2 = create_autospec(UNI)
1703 1
        uni1.interface = create_autospec(Interface)
1704 1
        uni2.interface = create_autospec(Interface)
1705 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1706 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1707 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1708
1709 1
        payload1 = {
1710
            "name": "my evc1",
1711
            "uni_a": {
1712
                "interface_id": "00:00:00:00:00:00:00:01:1",
1713
                "tag": {"tag_type": 'vlan', "value": 80},
1714
            },
1715
            "uni_z": {
1716
                "interface_id": "00:00:00:00:00:00:00:02:2",
1717
                "tag": {"tag_type": 'vlan', "value": 1},
1718
            },
1719
            "dynamic_backup_path": True,
1720
        }
1721
1722 1
        payload2 = {
1723
            "primary_path": [
1724
                {
1725
                    "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1726
                    "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1727
                }
1728
            ]
1729
        }
1730
1731 1
        evc_as_dict_mock.return_value = payload1
1732 1
        response = await self.api_client.post(
1733
            f"{self.base_endpoint}/v2/evc/",
1734
            json=payload1,
1735
        )
1736 1
        assert 201 == response.status_code
1737
1738 1
        evc_as_dict_mock.return_value = payload2
1739 1
        current_data = response.json()
1740 1
        circuit_id = current_data["circuit_id"]
1741 1
        response = await self.api_client.patch(
1742
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1743
            json=payload2,
1744
        )
1745
        current_data = response.json()
1746
        expected_data = "primary_path is not a valid path: error"
1747
        assert 400 == response.status_code
1748
        assert current_data["description"] == expected_data
1749
1750 1
    def test_link_from_dict_non_existent_intf(self):
1751
        """Test _link_from_dict non existent intf."""
1752 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1753 1
        link_dict = {
1754
            "endpoint_a": {"id": "a"},
1755
            "endpoint_b": {"id": "b"}
1756
        }
1757 1
        with pytest.raises(ValueError):
1758 1
            self.napp._link_from_dict(link_dict, "current_path")
1759
1760 1
    def test_link_from_dict_vlan_metadata(self):
1761
        """Test that link_from_dict only accepts vlans for current_path
1762
         and failover_path."""
1763 1
        intf = MagicMock(id="01:1")
1764 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=intf)
1765 1
        link_dict = {
1766
            'id': 'mock_link',
1767
            'endpoint_a': {'id': '00:00:00:00:00:00:00:01:4'},
1768
            'endpoint_b': {'id': '00:00:00:00:00:00:00:05:2'},
1769
            'metadata': {'s_vlan': {'tag_type': 'vlan', 'value': 1}}
1770
        }
1771 1
        link = self.napp._link_from_dict(link_dict, "current_path")
1772 1
        assert link.metadata.get('s_vlan', None)
1773
1774 1
        link = self.napp._link_from_dict(link_dict, "failover_path")
1775 1
        assert link.metadata.get('s_vlan', None)
1776
1777 1
        link = self.napp._link_from_dict(link_dict, "primary_path")
1778 1
        assert link.metadata.get('s_vlan', None) is None
1779
1780 1
    def test_uni_from_dict_non_existent_intf(self):
1781
        """Test _link_from_dict non existent intf."""
1782 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1783 1
        uni_dict = {
1784
            "interface_id": "aaa",
1785
        }
1786 1
        with pytest.raises(ValueError):
1787 1
            self.napp._uni_from_dict(uni_dict)
1788
1789 1 View Code Duplication
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1790 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1791 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1792 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1793 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1794 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1795 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1796 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1797 1
    async def test_update_evc_no_json_mime(
1798
        self,
1799
        mongo_controller_upsert_mock,
1800
        validate_mock,
1801
        uni_from_dict_mock,
1802
        sched_add_mock,
1803
        evc_deploy_mock,
1804
        mock_use_uni_tags,
1805
        mock_tags_equal,
1806
        mock_check_duplicate
1807
    ):
1808
        """Test update a circuit with wrong mimetype."""
1809 1
        self.napp.controller.loop = asyncio.get_running_loop()
1810 1
        validate_mock.return_value = True
1811 1
        sched_add_mock.return_value = True
1812 1
        evc_deploy_mock.return_value = True
1813 1
        mock_use_uni_tags.return_value = True
1814 1
        mock_tags_equal.return_value = True
1815 1
        mock_check_duplicate.return_value = True
1816 1
        uni1 = create_autospec(UNI)
1817 1
        uni2 = create_autospec(UNI)
1818 1
        uni1.interface = create_autospec(Interface)
1819 1
        uni2.interface = create_autospec(Interface)
1820 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1821 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1822 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1823 1
        mongo_controller_upsert_mock.return_value = True
1824
1825 1
        payload1 = {
1826
            "name": "my evc1",
1827
            "uni_a": {
1828
                "interface_id": "00:00:00:00:00:00:00:01:1",
1829
                "tag": {"tag_type": 'vlan', "value": 80},
1830
            },
1831
            "uni_z": {
1832
                "interface_id": "00:00:00:00:00:00:00:02:2",
1833
                "tag": {"tag_type": 'vlan', "value": 1},
1834
            },
1835
            "dynamic_backup_path": True,
1836
        }
1837
1838 1
        payload2 = {"dynamic_backup_path": False}
1839
1840 1
        response = await self.api_client.post(
1841
            f"{self.base_endpoint}/v2/evc/",
1842
            json=payload1,
1843
        )
1844 1
        assert 201 == response.status_code
1845
1846 1
        current_data = response.json()
1847 1
        circuit_id = current_data["circuit_id"]
1848 1
        response = await self.api_client.patch(
1849
            f"{self.base_endpoint}/v2/evc/{circuit_id}", data=payload2
1850
        )
1851
        current_data = response.json()
1852
        assert 415 == response.status_code
1853
        assert "application/json" in current_data["description"]
1854
1855 1
    async def test_delete_no_evc(self):
1856
        """Test delete when EVC does not exist."""
1857 1
        url = f"{self.base_endpoint}/v2/evc/123"
1858 1
        response = await self.api_client.delete(url)
1859
        current_data = response.json()
1860
        expected_data = "circuit_id 123 not found"
1861
        assert current_data["description"] == expected_data
1862
        assert 404 == response.status_code
1863
1864 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
1865 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1866 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_uni_tags")
1867 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1868 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_current_flows")
1869 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1870 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1871 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1872 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1873 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1874 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1875 1
    async def test_delete_archived_evc(
1876
        self,
1877
        evc_as_dict_mock,
1878
        validate_mock,
1879
        mongo_controller_upsert_mock,
1880
        uni_from_dict_mock,
1881
        sched_add_mock,
1882
        evc_deploy_mock,
1883
        remove_current_flows_mock,
1884
        mock_use_uni,
1885
        mock_remove_tags,
1886
        mock_tags_equal,
1887
        mock_check_duplicate
1888
    ):
1889
        """Try to delete an archived EVC"""
1890 1
        self.napp.controller.loop = asyncio.get_running_loop()
1891 1
        validate_mock.return_value = True
1892 1
        mongo_controller_upsert_mock.return_value = True
1893 1
        sched_add_mock.return_value = True
1894 1
        evc_deploy_mock.return_value = True
1895 1
        mock_use_uni.return_value = True
1896 1
        mock_tags_equal.return_value = True
1897 1
        mock_check_duplicate.return_value = True
1898 1
        uni1 = create_autospec(UNI)
1899 1
        uni2 = create_autospec(UNI)
1900 1
        uni1.interface = create_autospec(Interface)
1901 1
        uni2.interface = create_autospec(Interface)
1902 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1903 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1904 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1905
1906 1
        payload1 = {
1907
            "name": "my evc1",
1908
            "uni_a": {
1909
                "interface_id": "00:00:00:00:00:00:00:01:1",
1910
                "tag": {"tag_type": 'vlan', "value": 80},
1911
            },
1912
            "uni_z": {
1913
                "interface_id": "00:00:00:00:00:00:00:02:2",
1914
                "tag": {"tag_type": 'vlan', "value": 1},
1915
            },
1916
            "dynamic_backup_path": True,
1917
        }
1918
1919 1
        evc_as_dict_mock.return_value = payload1
1920 1
        response = await self.api_client.post(
1921
            f"{self.base_endpoint}/v2/evc/",
1922
            json=payload1
1923
        )
1924 1
        assert 201 == response.status_code
1925 1
        assert len(self.napp.circuits) == 1
1926 1
        current_data = response.json()
1927 1
        circuit_id = current_data["circuit_id"]
1928 1
        self.napp.circuits[circuit_id].archive()
1929
1930 1
        response = await self.api_client.delete(
1931
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1932
        )
1933 1
        assert 200 == response.status_code
1934 1
        assert mock_remove_tags.call_count == 0
1935 1
        assert remove_current_flows_mock.call_count == 0
1936 1
        assert len(self.napp.circuits) == 0
1937
1938 1
        response = await self.api_client.delete(
1939
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1940
        )
1941
        current_data = response.json()
1942
        expected_data = f"circuit_id {circuit_id} not found"
1943
        assert current_data["description"] == expected_data
1944
        assert 404 == response.status_code
1945
        assert len(self.napp.circuits) == 0
1946
1947 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1948 1
    async def test_delete_circuit(self, emit_event_mock):
1949
        """Test delete_circuit"""
1950 1
        evc = MagicMock()
1951 1
        evc.archived = False
1952 1
        circuit_id = '1'
1953 1
        self.napp.circuits[circuit_id] = evc
1954 1
        response = await self.api_client.delete(
1955
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1956
        )
1957 1
        assert 200 == response.status_code
1958 1
        assert evc.deactivate.call_count == 1
1959 1
        assert evc.disable.call_count == 1
1960 1
        evc.remove_current_flows.assert_called_once_with(
1961
            sync=False
1962
        )
1963 1
        evc.remove_failover_flows.assert_called_once_with(
1964
            sync=False
1965
        )
1966 1
        assert evc.archive.call_count == 1
1967 1
        assert evc.remove_uni_tags.call_count == 1
1968 1
        assert evc.sync.call_count == 1
1969 1
        assert not self.napp.circuits
1970 1
        assert emit_event_mock.call_count == 1
1971
1972 1
    def test_handle_link_up(self):
1973
        """Test handle_link_up method."""
1974 1
        evc_mock = create_autospec(EVC)
1975 1
        evc_mock.service_level, evc_mock.creation_time = 0, 1
1976 1
        evc_mock.is_enabled = MagicMock(side_effect=[
1977
            True, False, True, True, True
1978
        ])
1979 1
        evc_mock.lock = MagicMock()
1980 1
        evc_mock.archived = False
1981 1
        evcs = [evc_mock, evc_mock, evc_mock]
1982 1
        event = KytosEvent(name="test", content={"link": "abc"})
1983 1
        self.napp.circuits = dict(zip(["1", "2", "3"], evcs))
1984 1
        self.napp.handle_link_up(event)
1985 1
        assert evc_mock.handle_link_up.call_count == 2
1986 1
        evc_mock.handle_link_up.assert_called_with("abc")
1987
1988 1
    def test_handle_link_down(
1989
        self
1990
    ):
1991
        """Test handle_link_down method."""
1992 1
        evc1 = MagicMock(id="1")
1993 1
        evc1.is_affected_by_link.return_value = True
1994 1
        evc1.is_failover_path_affected_by_link.return_value = True
1995
1996 1
        evc2 = MagicMock(id="2")
1997 1
        evc2.is_affected_by_link.return_value = True
1998 1
        evc2.failover_path = Path([])
1999
2000 1
        default_undeploy = [evc1, evc2]
2001
2002 1
        evc3 = MagicMock(id="3")
2003 1
        evc3.is_affected_by_link.return_value = True
2004 1
        evc3.is_failover_path_affected_by_link.return_value = False
2005
2006 1
        evc4 = MagicMock(id="4")
2007 1
        evc4.is_affected_by_link.return_value = True
2008 1
        evc4.is_failover_path_affected_by_link.return_value = False
2009
2010 1
        default_swap_to_failover = [evc3, evc4]
2011
2012 1
        evc5 = MagicMock(id="5")
2013 1
        evc5.is_affected_by_link.return_value = False
2014 1
        evc5.is_failover_path_affected_by_link.return_value = True
2015
2016 1
        evc6 = MagicMock(id="6")
2017 1
        evc6.is_affected_by_link.return_value = False
2018 1
        evc6.is_failover_path_affected_by_link.return_value = True
2019
2020 1
        default_clear_failover = [evc5, evc6]
2021
2022 1
        self.napp.get_evcs_by_svc_level = MagicMock()
2023
2024 1
        self.napp.get_evcs_by_svc_level.return_value = [
2025
            evc1,
2026
            evc2,
2027
            evc3,
2028
            evc4,
2029
            evc5,
2030
            evc6,
2031
        ]
2032
2033 1
        self.napp.execute_swap_to_failover = MagicMock()
2034
2035 1
        swap_to_failover_success = [evc3]
2036 1
        swap_to_failover_failure = [evc4]
2037
2038 1
        self.napp.execute_swap_to_failover.return_value =\
2039
            swap_to_failover_success, swap_to_failover_failure
2040
2041 1
        self.napp.execute_clear_failover = MagicMock()
2042
2043 1
        clear_failover_success = [evc5, evc3]
2044 1
        clear_failover_failure = [evc6]
2045
2046 1
        self.napp.execute_clear_failover.return_value =\
2047
            clear_failover_success, clear_failover_failure
2048
2049 1
        self.napp.execute_undeploy = MagicMock()
2050
2051 1
        undeploy_success = [evc1, evc4, evc6]
2052 1
        undeploy_failure = [evc2]
2053
2054 1
        self.napp.execute_undeploy.return_value =\
2055
            undeploy_success, undeploy_failure
2056
2057 1
        link = MagicMock(id="123")
2058 1
        event = KytosEvent(name="test", content={"link": link})
2059
2060 1
        self.napp.handle_link_down(event)
2061
2062 1
        self.napp.execute_swap_to_failover.assert_called_with(
2063
            default_swap_to_failover
2064
        )
2065
2066 1
        self.napp.execute_clear_failover.assert_called_with(
2067
            [*default_clear_failover, *swap_to_failover_success]
2068
        )
2069
2070 1
        self.napp.execute_undeploy.assert_called_with([
2071
            *default_undeploy,
2072
            *swap_to_failover_failure,
2073
            *clear_failover_failure
2074
        ])
2075
2076 1
        self.napp.mongo_controller.update_evcs.assert_called_with([
2077
            evc3.as_dict(),
2078
            evc5.as_dict(),
2079
            evc1.as_dict(),
2080
            evc4.as_dict(),
2081
            evc6.as_dict(),
2082
        ])
2083
2084 1 View Code Duplication
    @patch("napps.kytos.mef_eline.main.emit_event")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2085 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2086 1
    def test_execute_swap_to_failover(
2087
        self,
2088
        send_flow_mods_mock: MagicMock,
2089
        emit_main_mock: MagicMock,
2090
    ):
2091
        """Test execute_swap_to_failover method."""
2092 1
        evc1 = MagicMock(id="1")
2093 1
        good_path = MagicMock(id="GoodPath")
2094 1
        bad_path = MagicMock(id="BadPath")
2095 1
        evc1.current_path = bad_path
2096 1
        evc1.failover_path = good_path
2097 1
        evc2 = MagicMock(id="2")
2098
2099 1
        self.napp.prepare_swap_to_failover_flow = {
2100
            evc1: {"1": ["Flow1"]},
2101
            evc2: None
2102
        }.get
2103
2104 1
        self.napp.prepare_swap_to_failover_event = {
2105
            evc1: "FailoverEvent1",
2106
        }.get
2107
2108 1
        success, failure = self.napp.execute_swap_to_failover([evc1, evc2])
2109
2110 1
        assert success == [evc1]
2111 1
        assert failure == [evc2]
2112
2113 1
        send_flow_mods_mock.assert_called_with(
2114
            {"1": ["Flow1"]},
2115
            "install"
2116
        )
2117
2118 1
        assert evc1.current_path == good_path
2119 1
        assert evc1.failover_path == bad_path
2120
2121 1
        emit_main_mock.assert_called_with(
2122
            self.napp.controller,
2123
            "failover_link_down",
2124
            content={"1": "FailoverEvent1"}
2125
        )
2126
2127 1 View Code Duplication
    @patch("napps.kytos.mef_eline.main.emit_event")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2128 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2129 1
    def test_execute_swap_to_failover_exception(
2130
        self,
2131
        send_flow_mods_mock: MagicMock,
2132
        emit_main_mock: MagicMock,
2133
    ):
2134
        """Test handle_link_down method when an exception occurs."""
2135 1
        evc1 = MagicMock(id="1")
2136 1
        good_path = MagicMock(id="GoodPath")
2137 1
        bad_path = MagicMock(id="BadPath")
2138 1
        evc1.current_path = bad_path
2139 1
        evc1.failover_path = good_path
2140 1
        evc2 = MagicMock(id="2")
2141
2142 1
        self.napp.prepare_swap_to_failover_flow = {
2143
            evc1: {"1": ["Flow1"]},
2144
            evc2: None
2145
        }.get
2146
2147 1
        self.napp.prepare_swap_to_failover_event = {
2148
            evc1: "FailoverEvent1",
2149
        }.get
2150
2151 1
        send_flow_mods_mock.side_effect = FlowModException(
2152
            "Flowmod failed to send"
2153
        )
2154
2155 1
        success, failure = self.napp.execute_swap_to_failover([evc1, evc2])
2156
2157 1
        assert success == []
2158 1
        assert failure == [evc1, evc2]
2159
2160 1
        send_flow_mods_mock.assert_called_with(
2161
            {"1": ["Flow1"]},
2162
            "install"
2163
        )
2164
2165 1
        assert evc1.current_path == bad_path
2166 1
        assert evc1.failover_path == good_path
2167
2168 1
        emit_main_mock.assert_not_called()
2169
2170 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2171 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2172 1
    def test_execute_clear_failover(
2173
        self,
2174
        send_flow_mods_mock: MagicMock,
2175
        emit_main_mock: MagicMock,
2176
    ):
2177
        """Test execute_clear_failover method."""
2178 1
        evc1 = MagicMock(id="1")
2179 1
        good_path = MagicMock(id="GoodPath")
2180 1
        bad_path = MagicMock(id="BadPath")
2181 1
        evc1.current_path = good_path
2182 1
        evc1.failover_path = bad_path
2183 1
        evc2 = MagicMock(id="2")
2184
2185 1
        self.napp.prepare_clear_failover_flow = {
2186
            evc1: {"1": ["Flow1"]},
2187
            evc2: None
2188
        }.get
2189
2190 1
        self.napp.prepare_clear_failover_event = {
2191
            evc1: "FailoverEvent1",
2192
        }.get
2193
2194 1
        success, failure = self.napp.execute_clear_failover([evc1, evc2])
2195
2196 1
        assert success == [evc1]
2197 1
        assert failure == [evc2]
2198
2199 1
        send_flow_mods_mock.assert_called_with(
2200
            {"1": ["Flow1"]},
2201
            "delete"
2202
        )
2203
2204 1
        assert evc1.current_path == good_path
2205 1
        assert not evc1.failover_path
2206
2207 1
        bad_path.make_vlans_available.assert_called_once_with(
2208
            self.napp.controller
2209
        )
2210
2211 1
        emit_main_mock.assert_called_with(
2212
            self.napp.controller,
2213
            "failover_old_path",
2214
            content={"1": "FailoverEvent1"}
2215
        )
2216
2217 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2218 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2219 1
    def test_execute_clear_failover_exception(
2220
        self,
2221
        send_flow_mods_mock: MagicMock,
2222
        emit_main_mock: MagicMock,
2223
    ):
2224
        """Test execute_clear_failover method when an exception occurs."""
2225 1
        evc1 = MagicMock(id="1")
2226 1
        good_path = MagicMock(id="GoodPath")
2227 1
        bad_path = MagicMock(id="BadPath")
2228 1
        evc1.current_path = good_path
2229 1
        evc1.failover_path = bad_path
2230 1
        evc2 = MagicMock(id="2")
2231
2232 1
        self.napp.prepare_clear_failover_flow = {
2233
            evc1: {"1": ["Flow1"]},
2234
            evc2: None
2235
        }.get
2236
2237 1
        self.napp.prepare_clear_failover_event = {
2238
            evc1: "FailoverEvent1",
2239
        }.get
2240
2241 1
        send_flow_mods_mock.side_effect = FlowModException(
2242
            "Flowmod failed to send"
2243
        )
2244
2245 1
        success, failure = self.napp.execute_clear_failover([evc1, evc2])
2246
2247 1
        assert success == []
2248 1
        assert failure == [evc1, evc2]
2249
2250 1
        send_flow_mods_mock.assert_called_with(
2251
            {"1": ["Flow1"]},
2252
            "delete"
2253
        )
2254
2255 1
        assert evc1.current_path == good_path
2256 1
        assert evc1.failover_path == bad_path
2257
2258 1
        emit_main_mock.assert_not_called()
2259
2260 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2261 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2262 1
    def test_execute_undeploy(
2263
        self,
2264
        send_flow_mods_mock: MagicMock,
2265
        emit_main_mock: MagicMock,
2266
    ):
2267
        """Test execute_undeploy method."""
2268 1
        evc1 = MagicMock(id="1")
2269 1
        bad_path1 = MagicMock(id="GoodPath")
2270 1
        bad_path2 = MagicMock(id="BadPath")
2271 1
        evc1.current_path = bad_path1
2272 1
        evc1.failover_path = bad_path2
2273 1
        evc2 = MagicMock(id="2")
2274
2275 1
        self.napp.prepare_undeploy_flow = {
2276
            evc1: {"1": ["Flow1"]},
2277
            evc2: None
2278
        }.get
2279
2280 1
        success, failure = self.napp.execute_undeploy([evc1, evc2])
2281
2282 1
        assert success == [evc1]
2283 1
        assert failure == [evc2]
2284
2285 1
        send_flow_mods_mock.assert_called_with(
2286
            {"1": ["Flow1"]},
2287
            "delete"
2288
        )
2289
2290 1
        assert not evc1.current_path
2291 1
        assert not evc1.failover_path
2292
2293 1
        assert evc2.current_path
2294 1
        assert evc2.failover_path
2295
2296 1
        bad_path1.make_vlans_available.assert_called_once_with(
2297
            self.napp.controller
2298
        )
2299 1
        bad_path2.make_vlans_available.assert_called_once_with(
2300
            self.napp.controller
2301
        )
2302
2303 1
        evc1.deactivate.assert_called()
2304 1
        evc2.deactivate.assert_not_called()
2305
2306 1
        emit_main_mock.assert_called_with(
2307
            self.napp.controller,
2308
            "need_redeploy",
2309
            content={"evc_id": "1"}
2310
        )
2311
2312 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2313 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2314 1
    def test_execute_undeploy_exception(
2315
        self,
2316
        send_flow_mods_mock: MagicMock,
2317
        emit_main_mock: MagicMock,
2318
    ):
2319
        """Test execute_undeploy method method when an exception occurs."""
2320 1
        evc1 = MagicMock(id="1")
2321 1
        bad_path1 = MagicMock(id="GoodPath")
2322 1
        bad_path2 = MagicMock(id="BadPath")
2323 1
        evc1.current_path = bad_path1
2324 1
        evc1.failover_path = bad_path2
2325 1
        evc2 = MagicMock(id="2")
2326
2327 1
        self.napp.prepare_undeploy_flow = {
2328
            evc1: {"1": ["Flow1"]},
2329
            evc2: None
2330
        }.get
2331
2332 1
        send_flow_mods_mock.side_effect = FlowModException(
2333
            "Flowmod failed to send"
2334
        )
2335
2336 1
        success, failure = self.napp.execute_undeploy([evc1, evc2])
2337
2338 1
        assert success == []
2339 1
        assert failure == [evc1, evc2]
2340
2341 1
        send_flow_mods_mock.assert_called_with(
2342
            {"1": ["Flow1"]},
2343
            "delete"
2344
        )
2345
2346 1
        assert evc1.current_path
2347 1
        assert evc1.failover_path
2348
2349 1
        assert evc2.current_path
2350 1
        assert evc2.failover_path
2351
2352 1
        bad_path1.make_vlans_available.assert_not_called()
2353 1
        bad_path2.make_vlans_available.assert_not_called()
2354
2355 1
        evc1.deactivate.assert_not_called()
2356 1
        evc2.deactivate.assert_not_called()
2357
2358 1
        emit_main_mock.assert_not_called()
2359
2360 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2361 1
    def test_handle_evc_affected_by_link_down(self, emit_event_mock):
2362
        """Test handle_evc_affected_by_link_down method."""
2363 1
        uni = create_autospec(UNI)
2364 1
        evc1 = MagicMock(
2365
            id="1",
2366
            metadata="data_mocked",
2367
            _active="true",
2368
            _enabled="false",
2369
            uni_a=uni,
2370
            uni_z=uni,
2371
        )
2372 1
        evc1.name = "name_mocked"
2373 1
        evc1.handle_link_down.return_value = True
2374 1
        evc2 = MagicMock(
2375
            id="2",
2376
            metadata="mocked_data",
2377
            _active="false",
2378
            _enabled="true",
2379
            uni_a=uni,
2380
            uni_z=uni,
2381
        )
2382 1
        evc2.name = "mocked_name"
2383 1
        evc2.handle_link_down.return_value = False
2384 1
        self.napp.circuits = {"1": evc1, "2": evc2}
2385
2386 1
        event = KytosEvent(name="e1", content={
2387
            "evc_id": "3",
2388
            "link": MagicMock(),
2389
        })
2390 1
        self.napp.handle_evc_affected_by_link_down(event)
2391 1
        emit_event_mock.assert_not_called()
2392 1
        event.content["evc_id"] = "1"
2393 1
        self.napp.handle_evc_affected_by_link_down(event)
2394 1
        emit_event_mock.assert_called_with(
2395
            self.napp.controller, "redeployed_link_down", content={
2396
                "id": "1",
2397
                "evc_id": "1",
2398
                "name": "name_mocked",
2399
                "metadata": "data_mocked",
2400
                "active": "true",
2401
                "enabled": "false",
2402
                "uni_a": uni.as_dict(),
2403
                "uni_z": uni.as_dict(),
2404
            }
2405
        )
2406
2407 1
        event.content["evc_id"] = "2"
2408 1
        self.napp.handle_evc_affected_by_link_down(event)
2409 1
        emit_event_mock.assert_called_with(
2410
            self.napp.controller, "error_redeploy_link_down", content={
2411
                "evc_id": "2",
2412
                "id": "2",
2413
                "name": "mocked_name",
2414
                "metadata": "mocked_data",
2415
                "active": "false",
2416
                "enabled": "true",
2417
                "uni_a": uni.as_dict(),
2418
                "uni_z": uni.as_dict(),
2419
            }
2420
        )
2421
2422 1
    async def test_add_metadata(self):
2423
        """Test method to add metadata"""
2424 1
        self.napp.controller.loop = asyncio.get_running_loop()
2425 1
        evc_mock = create_autospec(EVC)
2426 1
        evc_mock.metadata = {}
2427 1
        evc_mock.id = 1234
2428 1
        self.napp.circuits = {"1234": evc_mock}
2429
2430 1
        payload = {"metadata1": 1, "metadata2": 2}
2431 1
        response = await self.api_client.post(
2432
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2433
            json=payload
2434
        )
2435
2436 1
        assert response.status_code == 201
2437 1
        evc_mock.extend_metadata.assert_called_with(payload)
2438
2439 1
    async def test_add_metadata_malformed_json(self):
2440
        """Test method to add metadata with a malformed json"""
2441 1
        self.napp.controller.loop = asyncio.get_running_loop()
2442 1
        payload = b'{"metadata1": 1, "metadata2": 2,}'
2443 1
        response = await self.api_client.post(
2444
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2445
            content=payload,
2446
            headers={"Content-Type": "application/json"}
2447
        )
2448
2449
        assert response.status_code == 400
2450
        assert "body contains invalid API" in response.json()["description"]
2451
2452 1
    async def test_add_metadata_no_body(self):
2453
        """Test method to add metadata with no body"""
2454 1
        self.napp.controller.loop = asyncio.get_running_loop()
2455 1
        response = await self.api_client.post(
2456
            f"{self.base_endpoint}/v2/evc/1234/metadata"
2457
        )
2458
        assert response.status_code == 400
2459
        assert response.json()["description"] == \
2460
            "Missing required request body"
2461
2462 1
    async def test_add_metadata_no_evc(self):
2463
        """Test method to add metadata with no evc"""
2464 1
        self.napp.controller.loop = asyncio.get_running_loop()
2465 1
        payload = {"metadata1": 1, "metadata2": 2}
2466 1
        response = await self.api_client.post(
2467
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2468
            json=payload,
2469
        )
2470
        assert response.status_code == 404
2471
        assert response.json()["description"] == \
2472
            "circuit_id 1234 not found."
2473
2474 1
    async def test_add_metadata_wrong_content_type(self):
2475
        """Test method to add metadata with wrong content type"""
2476 1
        self.napp.controller.loop = asyncio.get_running_loop()
2477 1
        payload = {"metadata1": 1, "metadata2": 2}
2478 1
        response = await self.api_client.post(
2479
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2480
            data=payload,
2481
            headers={"Content-Type": "application/xml"}
2482
        )
2483
        assert response.status_code == 415
2484
        assert "application/xml" in response.json()["description"]
2485
2486 1
    async def test_get_metadata(self):
2487
        """Test method to get metadata"""
2488 1
        evc_mock = create_autospec(EVC)
2489 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2490 1
        evc_mock.id = 1234
2491 1
        self.napp.circuits = {"1234": evc_mock}
2492
2493 1
        response = await self.api_client.get(
2494
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2495
        )
2496 1
        assert response.status_code == 200
2497 1
        assert response.json() == {"metadata": evc_mock.metadata}
2498
2499 1
    async def test_delete_metadata(self):
2500
        """Test method to delete metadata"""
2501 1
        evc_mock = create_autospec(EVC)
2502 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2503 1
        evc_mock.id = 1234
2504 1
        self.napp.circuits = {"1234": evc_mock}
2505
2506 1
        response = await self.api_client.delete(
2507
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2508
        )
2509 1
        assert response.status_code == 200
2510
2511 1
    async def test_delete_metadata_no_evc(self):
2512
        """Test method to delete metadata with no evc"""
2513 1
        response = await self.api_client.delete(
2514
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2515
        )
2516
        assert response.status_code == 404
2517
        assert response.json()["description"] == \
2518
            "circuit_id 1234 not found."
2519
2520 1
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
2521 1
    def test_load_all_evcs(self, load_evc_mock):
2522
        """Test load_evcs method"""
2523 1
        mock_circuits = {
2524
            'circuits': {
2525
                1: 'circuit_1',
2526
                2: 'circuit_2',
2527
                3: 'circuit_3',
2528
                4: 'circuit_4'
2529
            }
2530
        }
2531 1
        self.napp.mongo_controller.get_circuits.return_value = mock_circuits
2532 1
        self.napp.circuits = {2: 'circuit_2', 3: 'circuit_3'}
2533 1
        self.napp.load_all_evcs()
2534 1
        load_evc_mock.assert_has_calls([call('circuit_1'), call('circuit_4')])
2535 1
        assert self.napp.controller.buffers.app.put.call_count > 1
2536 1
        call_args = self.napp.controller.buffers.app.put.call_args[0]
2537 1
        assert call_args[0].name == "kytos/mef_eline.evcs_loaded"
2538 1
        assert dict(call_args[0].content) == mock_circuits["circuits"]
2539 1
        timeout_d = {"timeout": 1}
2540 1
        assert self.napp.controller.buffers.app.put.call_args[1] == timeout_d
2541
2542 1
    @patch('napps.kytos.mef_eline.main.Main._evc_from_dict')
2543 1
    def test_load_evc(self, evc_from_dict_mock):
2544
        """Test _load_evc method"""
2545
        # pylint: disable=protected-access
2546
        # case 1: early return with ValueError exception
2547 1
        evc_from_dict_mock.side_effect = ValueError("err")
2548 1
        evc_dict = MagicMock()
2549 1
        assert not self.napp._load_evc(evc_dict)
2550
2551
        # case 2: early return with KytosTagError exception
2552 1
        evc_from_dict_mock.side_effect = KytosTagError("")
2553 1
        assert not self.napp._load_evc(evc_dict)
2554
2555
        # case 3: archived evc
2556 1
        evc = MagicMock()
2557 1
        evc.archived = True
2558 1
        evc_from_dict_mock.side_effect = None
2559 1
        evc_from_dict_mock.return_value = evc
2560 1
        assert not self.napp._load_evc(evc_dict)
2561
2562
        # case 4: success creating
2563 1
        evc.archived = False
2564 1
        evc.id = 1
2565 1
        self.napp.sched = MagicMock()
2566
2567 1
        result = self.napp._load_evc(evc_dict)
2568 1
        assert result == evc
2569 1
        self.napp.sched.add.assert_called_with(evc)
2570 1
        assert self.napp.circuits[1] == evc
2571
2572 1
    def test_handle_flow_mod_error(self):
2573
        """Test handle_flow_mod_error method"""
2574 1
        flow = MagicMock()
2575 1
        flow.cookie = 0xaa00000000000011
2576 1
        event = MagicMock()
2577 1
        event.content = {'flow': flow, 'error_command': 'add'}
2578 1
        evc = create_autospec(EVC)
2579 1
        evc.archived = False
2580 1
        evc.remove_current_flows = MagicMock()
2581 1
        evc.lock = MagicMock()
2582 1
        self.napp.circuits = {"00000000000011": evc}
2583 1
        self.napp.handle_flow_mod_error(event)
2584 1
        evc.remove_current_flows.assert_called_once()
2585
2586 1
    def test_handle_flow_mod_error_return(self):
2587
        """Test handle_flow_mod_error method with early return."""
2588 1
        flow = MagicMock()
2589 1
        flow.cookie = 0xaa00000000000011
2590 1
        event = MagicMock()
2591 1
        event.content = {'flow': flow, 'error_command': 'delete'}
2592
2593 1
        evc = create_autospec(EVC)
2594 1
        evc.archived = False
2595 1
        evc.is_enabled.return_value = True
2596
2597
        # Flow command is not 'add'
2598 1
        self.napp.circuits = {"00000000000011": evc}
2599 1
        self.napp.handle_flow_mod_error(event)
2600 1
        assert not evc.remove_current_flows.call_count
2601
2602
        # EVC is not enabled
2603 1
        event.content["error_command"] = "add"
2604 1
        evc.is_enabled.return_value = False
2605 1
        self.napp.handle_flow_mod_error(event)
2606 1
        assert not evc.remove_current_flows.call_count
2607
2608
        # EVC is archived
2609 1
        evc.is_enabled.return_value = True
2610 1
        evc.archived = True
2611 1
        self.napp.handle_flow_mod_error(event)
2612 1
        assert not evc.remove_current_flows.call_count
2613
2614
        # EVC does not exist in self.circuits
2615 1
        evc.archived = False
2616 1
        self.napp.circuits = {}
2617 1
        self.napp.handle_flow_mod_error(event)
2618 1
        assert not evc.remove_current_flows.call_count
2619
2620 1
    @patch("kytos.core.Controller.get_interface_by_id")
2621 1
    def test_uni_from_dict(self, _get_interface_by_id_mock):
2622
        """Test _uni_from_dict method."""
2623
        # pylint: disable=protected-access
2624
        # case1: early return on empty dict
2625 1
        assert not self.napp._uni_from_dict(None)
2626
2627
        # case2: invalid interface raises ValueError
2628 1
        _get_interface_by_id_mock.return_value = None
2629 1
        uni_dict = {
2630
            "interface_id": "00:01:1",
2631
            "tag": {"tag_type": 'vlan', "value": 81},
2632
        }
2633 1
        with pytest.raises(ValueError):
2634 1
            self.napp._uni_from_dict(uni_dict)
2635
2636
        # case3: success creation
2637 1
        uni_mock = get_uni_mocked(switch_id="00:01")
2638 1
        _get_interface_by_id_mock.return_value = uni_mock.interface
2639 1
        uni = self.napp._uni_from_dict(uni_dict)
2640 1
        assert uni == uni_mock
2641
2642
        # case4: success creation of tag list
2643 1
        uni_dict["tag"]["value"] = [[1, 10]]
2644 1
        uni = self.napp._uni_from_dict(uni_dict)
2645 1
        assert isinstance(uni.user_tag, TAGRange)
2646
2647
        # case5: success creation without tag
2648 1
        uni_mock.user_tag = None
2649 1
        del uni_dict["tag"]
2650 1
        uni = self.napp._uni_from_dict(uni_dict)
2651 1
        assert uni == uni_mock
2652
2653 1
    def test_handle_flow_delete(self):
2654
        """Test handle_flow_delete method"""
2655 1
        flow = MagicMock()
2656 1
        flow.cookie = 0xaa00000000000011
2657 1
        event = MagicMock()
2658 1
        event.content = {'flow': flow}
2659 1
        evc = create_autospec(EVC)
2660 1
        evc.set_flow_removed_at = MagicMock()
2661 1
        self.napp.circuits = {"00000000000011": evc}
2662 1
        self.napp.handle_flow_delete(event)
2663 1
        evc.set_flow_removed_at.assert_called_once()
2664
2665 1 View Code Duplication
    async def test_add_bulk_metadata(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2666
        """Test add_bulk_metadata method"""
2667 1
        self.napp.controller.loop = asyncio.get_running_loop()
2668 1
        evc_mock = create_autospec(EVC)
2669 1
        evc_mock.id = 1234
2670 1
        self.napp.circuits = {"1234": evc_mock}
2671 1
        payload = {
2672
            "circuit_ids": ["1234"],
2673
            "metadata1": 1,
2674
            "metadata2": 2
2675
        }
2676 1
        response = await self.api_client.post(
2677
            f"{self.base_endpoint}/v2/evc/metadata",
2678
            json=payload
2679
        )
2680 1
        assert response.status_code == 201
2681 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2682 1
        ids = payload.pop("circuit_ids")
2683 1
        assert args[0] == ids
2684 1
        assert args[1] == payload
2685 1
        assert args[2] == "add"
2686 1
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2687 1
        assert calls == 1
2688 1
        evc_mock.extend_metadata.assert_called_with(payload)
2689
2690 1
    async def test_add_bulk_metadata_empty_list(self):
2691
        """Test add_bulk_metadata method empty list"""
2692 1
        self.napp.controller.loop = asyncio.get_running_loop()
2693 1
        evc_mock = create_autospec(EVC)
2694 1
        evc_mock.id = 1234
2695 1
        self.napp.circuits = {"1234": evc_mock}
2696 1
        payload = {
2697
            "circuit_ids": [],
2698
            "metadata1": 1,
2699
            "metadata2": 2
2700
        }
2701 1
        response = await self.api_client.post(
2702
            f"{self.base_endpoint}/v2/evc/metadata",
2703
            json=payload
2704
        )
2705
        assert response.status_code == 400
2706
        assert "invalid" in response.json()["description"]
2707
2708 1
    async def test_add_bulk_metadata_no_id(self):
2709
        """Test add_bulk_metadata with unknown evc id"""
2710 1
        self.napp.controller.loop = asyncio.get_running_loop()
2711 1
        evc_mock = create_autospec(EVC)
2712 1
        evc_mock.id = 1234
2713 1
        self.napp.circuits = {"1234": evc_mock}
2714 1
        payload = {
2715
            "circuit_ids": ["1234", "4567"]
2716
        }
2717 1
        response = await self.api_client.post(
2718
            f"{self.base_endpoint}/v2/evc/metadata",
2719
            json=payload
2720
        )
2721
        assert response.status_code == 404
2722
2723 1
    async def test_add_bulk_metadata_no_circuits(self):
2724
        """Test add_bulk_metadata without circuit_ids"""
2725 1
        self.napp.controller.loop = asyncio.get_running_loop()
2726 1
        evc_mock = create_autospec(EVC)
2727 1
        evc_mock.id = 1234
2728 1
        self.napp.circuits = {"1234": evc_mock}
2729 1
        payload = {
2730
            "metadata": "data"
2731
        }
2732 1
        response = await self.api_client.post(
2733
            f"{self.base_endpoint}/v2/evc/metadata",
2734
            json=payload
2735
        )
2736
        assert response.status_code == 400
2737
2738 1 View Code Duplication
    async def test_delete_bulk_metadata(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2739
        """Test delete_metadata method"""
2740 1
        self.napp.controller.loop = asyncio.get_running_loop()
2741 1
        evc_mock = create_autospec(EVC)
2742 1
        evc_mock.id = 1234
2743 1
        self.napp.circuits = {"1234": evc_mock}
2744 1
        payload = {
2745
            "circuit_ids": ["1234"]
2746
        }
2747 1
        response = await self.api_client.request(
2748
            "DELETE",
2749
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2750
            json=payload
2751
        )
2752 1
        assert response.status_code == 200
2753 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2754 1
        assert args[0] == payload["circuit_ids"]
2755 1
        assert args[1] == {"metadata1": ""}
2756 1
        assert args[2] == "del"
2757 1
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2758 1
        assert calls == 1
2759 1
        assert evc_mock.remove_metadata.call_count == 1
2760
2761 1
    async def test_delete_bulk_metadata_error(self):
2762
        """Test bulk_delete_metadata with ciruit erroring"""
2763 1
        self.napp.controller.loop = asyncio.get_running_loop()
2764 1
        evc_mock = create_autospec(EVC)
2765 1
        evcs = [evc_mock, evc_mock]
2766 1
        self.napp.circuits = dict(zip(["1", "2"], evcs))
2767 1
        payload = {"circuit_ids": ["1", "2", "3"]}
2768 1
        response = await self.api_client.request(
2769
            "DELETE",
2770
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2771
            json=payload
2772
        )
2773
        assert response.status_code == 404, response.data
2774
        assert response.json()["description"] == ["3"]
2775
2776 1
    async def test_use_uni_tags(self):
2777
        """Test _use_uni_tags"""
2778 1
        self.napp.controller.loop = asyncio.get_running_loop()
2779 1
        evc_mock = create_autospec(EVC)
2780 1
        evc_mock.uni_a = "uni_a_mock"
2781 1
        evc_mock.uni_z = "uni_z_mock"
2782 1
        self.napp._use_uni_tags(evc_mock)
2783 1
        assert evc_mock._use_uni_vlan.call_count == 2
2784 1
        assert evc_mock._use_uni_vlan.call_args[0][0] == evc_mock.uni_z
2785
2786
        # One UNI tag is not available
2787 1
        evc_mock._use_uni_vlan.side_effect = [KytosTagError(""), None]
2788 1
        with pytest.raises(KytosTagError):
2789 1
            self.napp._use_uni_tags(evc_mock)
2790 1
        assert evc_mock._use_uni_vlan.call_count == 3
2791 1
        assert evc_mock.make_uni_vlan_available.call_count == 0
2792
2793 1
        evc_mock._use_uni_vlan.side_effect = [None, KytosTagError("")]
2794 1
        with pytest.raises(KytosTagError):
2795 1
            self.napp._use_uni_tags(evc_mock)
2796 1
        assert evc_mock._use_uni_vlan.call_count == 5
2797 1
        assert evc_mock.make_uni_vlan_available.call_count == 1
2798
2799 1
    def test_check_no_tag_duplication(self):
2800
        """Test _check_no_tag_duplication"""
2801 1
        evc = MagicMock()
2802 1
        evc.check_no_tag_duplicate = MagicMock()
2803 1
        evc.archived = False
2804 1
        evc.id = "1"
2805 1
        self.napp.circuits = {"1": evc}
2806 1
        evc_id = "2"
2807 1
        uni_a = get_uni_mocked(valid=True)
2808 1
        uni_z = get_uni_mocked(valid=True)
2809 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2810 1
        assert evc.check_no_tag_duplicate.call_count == 0
2811
2812 1
        uni_a.user_tag = None
2813 1
        uni_z.user_tag = None
2814 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2815 1
        assert evc.check_no_tag_duplicate.call_count == 2
2816
2817 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, None)
2818 1
        assert evc.check_no_tag_duplicate.call_count == 3
2819
2820 1
        self.napp._check_no_tag_duplication(evc_id, None, None)
2821 1
        assert evc.check_no_tag_duplicate.call_count == 3
2822
2823 1
    @patch("napps.kytos.mef_eline.main.time")
2824 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_up")
2825 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_down")
2826 1
    def test_handle_on_interface_link_change(
2827
        self,
2828
        mock_down,
2829
        mock_up,
2830
        mock_time
2831
    ):
2832
        """Test handle_on_interface_link_change"""
2833 1
        mock_time.sleep.return_value = True
2834 1
        mock_intf = Mock()
2835 1
        mock_intf.id = "mock_intf"
2836
2837
        # Created/link_up/enabled
2838 1
        name = '.*.switch.interface.created'
2839 1
        content = {"interface": mock_intf}
2840 1
        event = KytosEvent(name=name, content=content)
2841 1
        self.napp.handle_on_interface_link_change(event)
2842 1
        assert mock_down.call_count == 0
2843 1
        assert mock_up.call_count == 1
2844
2845 1
        name = '.*.interface.enabled'
2846 1
        content = {"interface": mock_intf}
2847 1
        event = KytosEvent(name=name, content=content)
2848 1
        self.napp.handle_on_interface_link_change(event)
2849 1
        assert mock_down.call_count == 0
2850 1
        assert mock_up.call_count == 2
2851
2852
        # Deleted/link_down/disabled
2853 1
        name = '.*.switch.interface.deleted'
2854 1
        event = KytosEvent(name=name, content=content)
2855 1
        self.napp.handle_on_interface_link_change(event)
2856 1
        assert mock_down.call_count == 1
2857 1
        assert mock_up.call_count == 2
2858
2859 1
        name = '.*.interface.down'
2860 1
        event = KytosEvent(name=name, content=content)
2861 1
        self.napp.handle_on_interface_link_change(event)
2862 1
        assert mock_down.call_count == 2
2863 1
        assert mock_up.call_count == 2
2864
2865
        # Event delay
2866 1
        self.napp._intf_events[mock_intf.id]["last_acquired"] = "mock_time"
2867 1
        for _ in range(1, 6):
2868 1
            self.napp.handle_on_interface_link_change(event)
2869 1
        assert mock_down.call_count == 2
2870 1
        assert mock_up.call_count == 2
2871
2872 1
        self.napp._intf_events[mock_intf.id].pop("last_acquired")
2873 1
        self.napp.handle_on_interface_link_change(event)
2874 1
        assert mock_down.call_count == 3
2875 1
        assert mock_up.call_count == 2
2876
2877
        # Out of order event
2878 1
        event = KytosEvent(name=name, content=content)
2879 1
        self.napp._intf_events[mock_intf.id]["event"] = Mock(timestamp=now())
2880
2881 1
        self.napp.handle_on_interface_link_change(event)
2882 1
        assert mock_down.call_count == 3
2883 1
        assert mock_up.call_count == 2
2884
2885 1
    def test_handle_evc_deployed(
2886
        self,
2887
    ):
2888
        """
2889
        Test setting up failover path with need_failover event.
2890
        """
2891 1
        evc1 = MagicMock()
2892 1
        evc1.is_eligible_for_failover_path.return_value = True
2893 1
        evc1.is_active.return_value = True
2894 1
        evc1.failover_path = Path([])
2895 1
        evc1.current_path = ["LINK"]
2896
2897 1
        evc2 = MagicMock()
2898 1
        evc2.is_eligible_for_failover_path.return_value = False
2899 1
        evc2.is_active.return_value = True
2900 1
        evc2.failover_path = Path([])
2901 1
        evc2.current_path = ["LINK"]
2902
2903 1
        self.napp.circuits = {
2904
            "evc_1": evc1,
2905
            "evc_2": evc2,
2906
        }
2907
2908 1
        event = KytosEvent(
2909
            name="kytos/mef_eline.need_failover",
2910
            content={
2911
                "evc_id": "evc_1",
2912
            }
2913
        )
2914
2915 1
        self.napp.handle_evc_deployed(event)
2916 1
        evc1.setup_failover_path.assert_called()
2917
2918 1
        event = KytosEvent(
2919
            name="kytos/mef_eline.need_failover",
2920
            content={
2921
                "evc_id": "evc_2",
2922
            }
2923
        )
2924
2925 1
        self.napp.handle_evc_deployed(event)
2926
        evc2.setup_failover_path.assert_not_called()
2927