TestMain.test_handle_link_down()   B
last analyzed

Complexity

Conditions 1

Size

Total Lines 94
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 63
nop 1
dl 0
loc 94
ccs 43
cts 43
cp 1
crap 1
rs 8.2109
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
"""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