Passed
Push — master ( e1b2c4...fc5519 )
by Vinicius
04:01 queued 10s
created

TestMain.test_create_circuit_already_enabled()   B

Complexity

Conditions 1

Size

Total Lines 69
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 1.0016

Importance

Changes 0
Metric Value
cc 1
eloc 57
nop 10
dl 0
loc 69
ccs 30
cts 34
cp 0.8824
crap 1.0016
rs 8.4072
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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