Test Failed
Pull Request — master (#690)
by
unknown
04:37
created

TestMain.test_delete_archived_evc()   B

Complexity

Conditions 1

Size

Total Lines 82
Code Lines 70

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 1.0011

Importance

Changes 0
Metric Value
cc 1
eloc 70
nop 12
dl 0
loc 82
ccs 43
cts 48
cp 0.8958
crap 1.0011
rs 7.9818
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
    @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 1
            mock_emit_event,
119 1
            mock_map_evc,
120
        ) = args
121
122
        mock_map_evc.side_effect = lambda x: x
123 1
124 1
        stored_circuits = {'1': {'name': 'circuit_1'},
125 1
                           '2': {'name': 'circuit_2'},
126 1
                           '3': {'name': 'circuit_3'}}
127 1
        mongo_controller_upsert_mock.return_value = True
128 1
        self.napp.mongo_controller.get_circuits.return_value = {
129 1
            "circuits": stored_circuits
130 1
        }
131 1
132 1
        mock_settings.WAIT_FOR_OLD_PATH = -1
133 1
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
        evc1.execution_rounds = 0
141 1
142
        evc2 = MagicMock(id=2, service_level=7, creation_time=1)
143
        evc2.is_enabled.return_value = True
144
        evc2.is_active.return_value = False
145
        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 1
150 1
        evc3 = MagicMock(id=3, service_level=0, creation_time=1)
151 1
        evc3.is_enabled.return_value = True
152
        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
        evc3.failover_path = Path([])
159 1
160
        self.napp.circuits = {
161 1
            '1': evc1,
162 1
            '2': evc2,
163 1
            '3': evc3,
164
        }
165
        assert self.napp.get_evcs_by_svc_level() == [
166
            evc2,
167 1
            evc1,
168 1
            evc3
169 1
        ]
170 1
171 1
        mock_check_list_traces.return_value = {
172 1
            1: True,
173 1
            2: False,
174 1
            3: True,
175 1
        }
176 1
177 1
        self.napp.execute_consistency()
178 1
        assert evc1.activate.call_count == 1
179
        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 1
            self.napp.controller,
184 1
            "need_failover",
185 1
            content=evc3
186
        )
187 1
188 1
    @patch('napps.kytos.mef_eline.main.settings')
189 1
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
190
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
191
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_list_traces")
192
    def test_execute_consistency_wait_for(self, mock_check_list_traces, *args):
193
        """Test execute and wait for setting."""
194
        (mongo_controller_upsert_mock, _, mock_settings) = args
195 1
196 1
        stored_circuits = {'1': {'name': 'circuit_1'}}
197 1
        mongo_controller_upsert_mock.return_value = True
198
        self.napp.mongo_controller.get_circuits.return_value = {
199
            "circuits": stored_circuits
200
        }
201
202
        mock_settings.WAIT_FOR_OLD_PATH = -1
203
        evc1 = MagicMock(id=1, service_level=0, creation_time=1)
204
        evc1.is_enabled.return_value = True
205
        evc1.is_active.return_value = False
206
        evc1.lock.locked.return_value = False
207
        evc1.has_recent_removed_flow.return_value = False
208
        evc1.is_recent_updated.return_value = False
209
        evc1.execution_rounds = 0
210
        evc1.deploy.call_count = 0
211
        self.napp.circuits = {'1': evc1}
212
        assert self.napp.get_evcs_by_svc_level() == [evc1]
213 1
        mock_settings.WAIT_FOR_OLD_PATH = 1
214 1
215 1
        mock_check_list_traces.return_value = {1: False}
216 1
217 1
        self.napp.execute_consistency()
218 1
        assert evc1.deploy.call_count == 0
219 1
        self.napp.execute_consistency()
220
        assert evc1.deploy.call_count == 1
221 1
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
        _validate_mock.return_value = True
231
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
232
        payload = {
233 1
            "name": "my evc1",
234 1
            "uni_a": {
235 1
                "interface_id": "00:00:00:00:00:00:00:01:1",
236 1
                "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
        evc_response = self.napp._evc_from_dict(payload)
249
        assert evc_response is not None
250
        assert evc_response.uni_a is not None
251
        assert evc_response.uni_z is not None
252
        assert evc_response.circuit_scheduler is not None
253
        assert evc_response.name is not None
254
        assert evc_response.queue_id is not None
255
256
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
257
    @patch("napps.kytos.mef_eline.models.evc.EVCBase._validate")
258
    @patch("kytos.core.Controller.get_interface_by_id")
259
    def test_evc_from_dict_paths(
260
        self, _get_interface_by_id_mock, _validate_mock, uni_from_dict_mock
261 1
    ):
262 1
        """
263 1
        Test the helper method that create an EVN from dict.
264 1
265 1
        Verify object creation with circuit data and schedule data.
266 1
        """
267 1
268 1
        _get_interface_by_id_mock.return_value = get_uni_mocked().interface
269 1
        _validate_mock.return_value = True
270
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
271 1
        payload = {
272 1
            "name": "my evc1",
273 1
            "uni_a": {
274 1
                "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 1
            "primary_path": [
283 1
                {
284 1
                    "endpoint_a": {
285 1
                        "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
        evc_response = self.napp._evc_from_dict(payload)
297
        assert evc_response is not None
298
        assert evc_response.uni_a is not None
299
        assert evc_response.uni_z is not None
300
        assert evc_response.circuit_scheduler is not None
301
        assert evc_response.name is not None
302
        assert len(evc_response.current_path) == 0
303
        assert len(evc_response.backup_path) == 0
304
        assert len(evc_response.primary_path) == 1
305
306
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
307
    @patch("napps.kytos.mef_eline.models.evc.EVCBase._validate")
308
    @patch("kytos.core.Controller.get_interface_by_id")
309
    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 1
        Verify object creation with circuit data and schedule data.
316 1
        """
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 1
            "name": "my evc1",
322 1
            "uni_a": {
323 1
                "interface_id": "00:00:00:00:00:00:00:01:1",
324
                "tag": {"tag_type": 'vlan', "value": 80},
325 1
            },
326
            "uni_z": {
327 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
328 1
                "tag": {"tag_type": 'vlan', "value": 1},
329 1
            },
330 1
            "primary_links": [
331 1
                {
332 1
                    "endpoint_a": {
333
                        "interface_id": "00:00:00:00:00:00:00:01:1"
334 1
                    },
335
                    "endpoint_b": {
336 1
                        "interface_id": "00:00:00:00:00:00:00:02:2"
337 1
                    },
338
                    "metadata": {
339 1
                        "s_vlan": {
340 1
                            "tag_type": 'vlan',
341 1
                            "value": 100
342 1
                        }
343
                    },
344 1
                }
345
            ],
346 1
            "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
        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
        assert len(evc_response.primary_links) == 1
359 1
360
    async def test_list_without_circuits(self):
361 1
        """Test if list circuits return 'no circuit stored.'."""
362
        circuits = {"circuits": {}}
363
        self.napp.mongo_controller.get_circuits.return_value = circuits
364
        url = f"{self.base_endpoint}/v2/evc/"
365
        response = await self.api_client.get(url)
366
        assert response.status_code == 200, response.data
367 1
        assert not response.json()
368 1
369
    async def test_list_no_circuits_stored(self):
370 1
        """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
        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
        circuits = {
382
            'circuits':
383
            {"1": {"name": "circuit_1"}, "2": {"name": "circuit_2"}}
384
        }
385 1
        get_circuits = self.napp.mongo_controller.get_circuits
386
        get_circuits.return_value = circuits
387 1
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
        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 1
        """Test if list circuits only archived circuits."""
396
        circuits = {
397 1
            'circuits':
398 1
            {
399 1
                "1": {"name": "circuit_1", "archived": True},
400 1
            }
401
        }
402 1
        get_circuits = self.napp.mongo_controller.get_circuits
403
        get_circuits.return_value = circuits
404 1
405 1
        url = f"{self.base_endpoint}/v2/evc/?archived=true&metadata.a=1"
406 1
        response = await self.api_client.get(url)
407
        get_circuits.assert_called_with(archived="true",
408
                                        metadata={"metadata.a": "1"})
409
        expected_result = {"1": circuits["circuits"]["1"]}
410 1
        assert response.json() == expected_result
411 1
412 1
    async def test_list_with_archived_circuits_all(self):
413 1
        """Test if list circuits return all circuits."""
414 1
        circuits = {
415 1
            'circuits': {
416 1
                "1": {"name": "circuit_1"},
417 1
                "2": {"name": "circuit_2", "archived": True},
418 1
            }
419 1
        }
420
        self.napp.mongo_controller.get_circuits.return_value = circuits
421
422
        url = f"{self.base_endpoint}/v2/evc/?archived=null"
423
        response = await self.api_client.get(url)
424
        expected_result = circuits["circuits"]
425
        assert response.json() == expected_result
426
427
    async def test_circuit_with_valid_id(self):
428
        """Test if get_circuit return the circuit attributes."""
429
        circuit = {"name": "circuit_1"}
430
        self.napp.mongo_controller.get_circuit.return_value = circuit
431
432
        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 1
437 1
    async def test_circuit_with_invalid_id(self):
438 1
        """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 1
        expected_result = "circuit_id 3 not found"
443 1
        assert response.json()["description"] == expected_result
444 1
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
    @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
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
454
    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
        self.napp.controller.loop = asyncio.get_running_loop()
469
        validate_mock.return_value = True
470
        mongo_controller_upsert_mock.return_value = True
471
        evc_deploy_mock.return_value = True
472
        mock_use_uni_tags.return_value = True
473
        mock_tags_equal.return_value = True
474
        mock_check_duplicate.return_value = True
475
        uni1 = create_autospec(UNI)
476
        uni2 = create_autospec(UNI)
477
        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
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
481
        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
        self.napp.mongo_controller.get_circuits.return_value = {}
485
486 1
        url = f"{self.base_endpoint}/v2/evc/"
487 1
        payload = {
488 1
            "name": "my evc1",
489
            "frequency": "* * * * *",
490
            "uni_a": {
491 1
                "interface_id": "00:00:00:00:00:00:00:01:1",
492 1
                "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 1
                }
504
            },
505
            "secondary_constraints": {
506 1
                "spf_attribute": "priority",
507
                "mandatory_metrics": {
508 1
                    "ownership": "blue"
509
                }
510 1
            }
511
        }
512 1
513 1
        response = await self.api_client.post(url, json=payload)
514
        current_data = response.json()
515 1
516
        # verify expected result from request
517
        assert 201 == response.status_code
518
        assert "circuit_id" in current_data
519
520 1
        # verify uni called
521
        uni_from_dict_mock.called_twice()
522
        uni_from_dict_mock.assert_any_call(payload["uni_z"])
523 1
        uni_from_dict_mock.assert_any_call(payload["uni_a"])
524 1
525
        # verify validation called
526 1
        validate_mock.assert_called_once()
527
        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 1
            primary_constraints=payload["primary_constraints"],
535 1
            secondary_constraints=payload["secondary_constraints"],
536 1
        )
537
        # verify save method is called
538
        mongo_controller_upsert_mock.assert_called_once()
539
540
        # verify evc as dict is called to save in the box
541
        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 1
        """Test create a new circuit trying to send request without a json."""
547 1
        self.napp.controller.loop = asyncio.get_running_loop()
548
        url = f"{self.base_endpoint}/v2/evc/"
549 1
550
        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
    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
        self.napp.controller.loop = asyncio.get_running_loop()
559
        url = f"{self.base_endpoint}/v2/evc/"
560
561
        response = await self.api_client.post(
562 1
            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
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
570
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
571
    async def test_create_a_circuit_case_4(
572 1
        self,
573 1
        mongo_controller_upsert_mock,
574 1
        uni_from_dict_mock
575 1
    ):
576 1
        """Test create a new circuit trying to send request with an
577 1
        invalid value."""
578 1
        self.napp.controller.loop = asyncio.get_running_loop()
579 1
        # 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
        url = f"{self.base_endpoint}/v2/evc/"
583
584
        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 1
        }
596 1
597 1
        response = await self.api_client.post(url, json=payload)
598 1
        current_data = response.json()
599 1
        expected_data = "Error creating UNI: Invalid value"
600 1
        assert 400 == response.status_code
601 1
        assert current_data["description"] == expected_data
602 1
603 1
        payload["name"] = 1
604 1
        response = await self.api_client.post(url, json=payload)
605 1
        assert 400 == response.status_code, response.data
606 1
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
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
616 1
    async def test_create_a_circuit_case_5(
617 1
        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
        self.napp.controller.loop = asyncio.get_running_loop()
631
        validate_mock.return_value = True
632
        mongo_controller_upsert_mock.return_value = True
633
        evc_deploy_mock.return_value = True
634
        mock_use_uni_tags.return_value = True
635
        mock_tags_equal.return_value = True
636
        mock_check_duplicate.return_value = True
637
        uni1 = create_autospec(UNI)
638
        uni2 = create_autospec(UNI)
639
        uni1.interface = create_autospec(Interface)
640
        uni2.interface = create_autospec(Interface)
641
        switch = MagicMock()
642
        switch.status = EntityStatus.DISABLED
643 1
        switch.return_value = "00:00:00:00:00:00:00:01"
644 1
        uni1.interface.switch = switch
645
        uni2.interface.switch = switch
646
        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
        self.napp.mongo_controller.get_circuits.return_value = {}
650
651 1
        url = f"{self.base_endpoint}/v2/evc/"
652 1
        payload = {
653 1
            "name": "my evc1",
654
            "frequency": "* * * * *",
655
            "uni_a": {
656 1
                "interface_id": "00:00:00:00:00:00:00:01:1",
657 1
                "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 1
                }
669
            },
670
            "secondary_constraints": {
671 1
                "spf_attribute": "priority",
672
                "mandatory_metrics": {
673 1
                    "ownership": "blue"
674
                }
675 1
            }
676 1
        }
677 1
678 1
        response = await self.api_client.post(url, json=payload)
679 1
        current_data = response.json()
680 1
681 1
        # verify expected result from request
682 1
        assert 201 == response.status_code
683 1
        assert "circuit_id" in current_data
684 1
685
        # verify uni called
686
        uni_from_dict_mock.called_twice()
687
        uni_from_dict_mock.assert_any_call(payload["uni_z"])
688
        uni_from_dict_mock.assert_any_call(payload["uni_a"])
689
690
        # verify validation called
691
        validate_mock.assert_called_once()
692
        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 1
            dynamic_backup_path=True,
699 1
            primary_constraints=payload["primary_constraints"],
700 1
            secondary_constraints=payload["secondary_constraints"],
701 1
        )
702 1
        # verify save method is called
703 1
        mongo_controller_upsert_mock.assert_called_once()
704 1
705 1
        # verify evc as dict is called to save in the box
706 1
        evc_as_dict_mock.assert_called()
707 1
        # verify add circuit in sched
708 1
        sched_add_mock.assert_called_once()
709 1
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
    async def test_create_a_circuit_case_6(
720 1
        self,
721 1
        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
        self.napp.controller.loop = asyncio.get_running_loop()
734
        validate_mock.return_value = True
735
        mongo_controller_upsert_mock.return_value = True
736
        evc_deploy_mock.return_value = True
737
        mock_use_uni_tags.return_value = True
738
        mock_tags_equal.return_value = True
739
        mock_check_duplicate.return_value = True
740
        uni1 = create_autospec(UNI)
741
        uni2 = create_autospec(UNI)
742
        uni1.interface = create_autospec(Interface)
743
        uni2.interface = create_autospec(Interface)
744
        switch = MagicMock()
745
        switch.status = EntityStatus.UP
746
        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
        uni2.interface.switch = switch
750
        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
        self.napp.mongo_controller.get_circuits.return_value = {}
754
755 1
        url = f"{self.base_endpoint}/v2/evc/"
756 1
        payload = {
757 1
            "name": "my evc1",
758
            "frequency": "* * * * *",
759
            "uni_a": {
760 1
                "interface_id": "00:00:00:00:00:00:00:01:1",
761 1
                "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 1
                }
773
            },
774
            "secondary_constraints": {
775 1
                "spf_attribute": "priority",
776
                "mandatory_metrics": {
777 1
                    "ownership": "blue"
778
                }
779 1
            }
780
        }
781 1
782 1
        response = await self.api_client.post(url, json=payload)
783
        current_data = response.json()
784 1
785
        # verify expected result from request
786
        assert 201 == response.status_code
787
        assert "circuit_id" in current_data
788
789
        # verify uni called
790
        uni_from_dict_mock.called_twice()
791
        uni_from_dict_mock.assert_any_call(payload["uni_z"])
792
        uni_from_dict_mock.assert_any_call(payload["uni_a"])
793
794
        # verify validation called
795
        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 1
            primary_constraints=payload["primary_constraints"],
804 1
            secondary_constraints=payload["secondary_constraints"],
805 1
        )
806 1
        # verify save method is called
807 1
        mongo_controller_upsert_mock.assert_called_once()
808 1
809 1
        # verify evc as dict is called to save in the box
810 1
        evc_as_dict_mock.assert_called()
811 1
        # verify add circuit in sched
812 1
        sched_add_mock.assert_called_once()
813
814
    async def test_create_a_circuit_invalid_queue_id(self):
815
        """Test create a new circuit with invalid queue_id."""
816
        self.napp.controller.loop = asyncio.get_running_loop()
817
        url = f"{self.base_endpoint}/v2/evc/"
818
819
        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 1
            "uni_z": {
827 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
828 1
                "tag": {"tag_type": 'vlan', "value": 1},
829 1
            },
830 1
        }
831 1
        response = await self.api_client.post(url, json=payload)
832 1
        current_data = response.json()
833 1
        expected_data = "8 is greater than the maximum of 7"
834
835
        assert response.status_code == 400
836 1
        assert expected_data in current_data["description"]
837 1
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
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
844 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
845
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
846
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
847
    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 1
        mock_check_duplicate
858 1
    ):
859
        """Test create an already created circuit."""
860
        # pylint: disable=too-many-locals
861
        self.napp.controller.loop = asyncio.get_running_loop()
862 1
        validate_mock.return_value = True
863
        mongo_controller_upsert_mock.return_value = True
864 1
        sched_add_mock.return_value = True
865
        evc_deploy_mock.return_value = True
866
        mock_tags_equal.return_value = True
867
        mock_check_duplicate.return_value = True
868
        mock_use_uni_tags.side_effect = [
869
            None, KytosTagError("The EVC already exists.")
870
        ]
871
        uni1 = create_autospec(UNI)
872
        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
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
877
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
878
879
        payload = {
880
            "name": "my evc1",
881 1
            "uni_a": {
882 1
                "interface_id": "00:00:00:00:00:00:00:01:1",
883 1
                "tag": {"tag_type": 'vlan', "value": 80},
884 1
            },
885 1
            "uni_z": {
886 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
887 1
                "tag": {"tag_type": 'vlan', "value": 1},
888 1
            },
889 1
            "dynamic_backup_path": True,
890 1
        }
891
892 1
        evc_as_dict_mock.return_value = payload
893
        response = await self.api_client.post(
894
            f"{self.base_endpoint}/v2/evc/",
895
            json=payload
896
        )
897
        assert 201 == response.status_code
898
899
        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 1
        assert current_data["description"] == expected_data
906
        assert 400 == response.status_code
907
908
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
909
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
910
    async def test_create_circuit_case_5(
911
        self,
912 1
        uni_from_dict_mock,
913 1
        mock_tags_equal
914
    ):
915 1
        """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
        uni1 = create_autospec(UNI)
920
        uni2 = create_autospec(UNI)
921
        uni1.interface = create_autospec(Interface)
922
        uni2.interface = create_autospec(Interface)
923
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
924
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
925
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
926
927 1
        payload = {
928
            "name": "my evc1",
929
            "frequency": "* * * * *",
930 1
            "uni_a": {
931
                "interface_id": "00:00:00:00:00:00:00:01:1",
932 1
                "tag": {"tag_type": 'vlan', "value": 80},
933 1
            },
934 1
            "uni_z": {
935 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
936 1
                "tag": {"tag_type": 'vlan', "value": 1},
937 1
            },
938 1
        }
939
940
        response = await self.api_client.post(url, json=payload)
941 1
        current_data = response.json()
942
        expected_data = "The EVC must have a primary path "
943 1
        expected_data += "or allow dynamic paths."
944 1
        assert 400 == response.status_code, response.data
945 1
        assert current_data["description"] == expected_data
946 1
947
    @patch("napps.kytos.mef_eline.main.Main._evc_from_dict")
948
    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 1
            },
958
            "uni_z": {
959 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
960 1
            },
961 1
        }
962 1
        response = await self.api_client.post(url, json=payload)
963 1
        assert response.status_code == 400, response.data
964 1
965 1
    async def test_redeploy_evc(self):
966 1
        """Test endpoint to redeploy an EVC."""
967
        evc1 = MagicMock()
968 1
        evc1.is_enabled.return_value = True
969
        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 1
            sync=False, return_path=True
975
        )
976
        assert response.status_code == 202, response.data
977 1
978
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
979 1
        url = url + "?try_avoid_same_s_vlan=false"
980
        response = await self.api_client.patch(url)
981 1
        evc1.remove_current_flows.assert_called_with(
982
            sync=False, return_path=False
983 1
        )
984 1
985 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
986
        url = url + "?try_avoid_same_s_vlan=True"
987 1
        response = await self.api_client.patch(url)
988
        evc1.remove_current_flows.assert_called_with(
989 1
            sync=False, return_path=True
990 1
        )
991
992
    async def test_redeploy_evc_disabled(self):
993
        """Test endpoint to redeploy an EVC."""
994
        evc1 = MagicMock()
995
        evc1.is_enabled.return_value = False
996
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
997
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
998
        response = await self.api_client.patch(url)
999
        evc1.remove_failover_flows.assert_not_called()
1000
        evc1.remove_current_flows.assert_not_called()
1001
        assert response.status_code == 409, response.data
1002
1003
    async def test_redeploy_evc_deleted(self):
1004
        """Test endpoint to redeploy an EVC."""
1005
        evc1 = MagicMock()
1006 1
        evc1.is_enabled.return_value = True
1007 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
1008
        url = f"{self.base_endpoint}/v2/evc/3/redeploy"
1009
        response = await self.api_client.patch(url)
1010
        assert response.status_code == 404, response.data
1011
1012
    async def test_list_schedules__no_data_stored(self):
1013
        """Test if list circuits return all circuits stored."""
1014
        self.napp.mongo_controller.get_circuits.return_value = {"circuits": {}}
1015
1016
        url = f"{self.base_endpoint}/v2/evc/schedule"
1017
1018
        response = await self.api_client.get(url)
1019
        assert response.status_code == 200
1020
        assert not response.json()
1021
1022
    def _add_mongodb_schedule_data(self, data_mock):
1023 1
        """Add schedule data to mongodb mock object."""
1024 1
        circuits = {"circuits": {}}
1025
        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 1
            "circuit_scheduler": [
1037
                {"id": "1", "frequency": "* * * * *", "action": "create"},
1038 1
                {"id": "2", "frequency": "1 * * * *", "action": "remove"},
1039
            ],
1040 1
        }
1041
        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 1
                "interface_id": "00:00:00:00:00:00:00:01:2",
1047
                "tag": {"tag_type": 'vlan', "value": 90},
1048
            },
1049 1
            "uni_z": {
1050
                "interface_id": "00:00:00:00:00:00:00:03:2",
1051 1
                "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
        circuits["circuits"].update({"bb:bb:bb": payload_2})
1059
        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
        circuits["circuits"].update({"cc:cc:cc": payload_3})
1072
        # Add one circuit to the mongodb.
1073
        data_mock.return_value = circuits
1074
1075
    async def test_list_schedules_from_mongodb(self):
1076
        """Test if list circuits return specific circuits stored."""
1077
        self._add_mongodb_schedule_data(
1078
            self.napp.mongo_controller.get_circuits
1079
        )
1080
1081
        url = f"{self.base_endpoint}/v2/evc/schedule"
1082
1083
        # Call URL
1084
        response = await self.api_client.get(url)
1085
        # Expected JSON data from response
1086
        expected = [
1087
            {
1088
                "circuit_id": "aa:aa:aa",
1089
                "schedule": {
1090 1
                    "action": "create",
1091 1
                    "frequency": "* * * * *",
1092
                    "id": "1",
1093 1
                },
1094
                "schedule_id": "1",
1095 1
            },
1096
            {
1097
                "circuit_id": "aa:aa:aa",
1098
                "schedule": {
1099 1
                    "action": "remove",
1100 1
                    "frequency": "1 * * * *",
1101 1
                    "id": "2",
1102 1
                },
1103 1
                "schedule_id": "2",
1104
            },
1105
            {
1106 1
                "circuit_id": "bb:bb:bb",
1107
                "schedule": {
1108
                    "action": "create",
1109 1
                    "frequency": "1 * * * *",
1110
                    "id": "3",
1111
                },
1112
                "schedule_id": "3",
1113
            },
1114 1
            {
1115 1
                "circuit_id": "bb:bb:bb",
1116
                "schedule": {
1117 1
                    "action": "remove",
1118
                    "frequency": "2 * * * *",
1119 1
                    "id": "4",
1120 1
                },
1121 1
                "schedule_id": "4",
1122
            },
1123
        ]
1124 1
1125
        assert response.status_code == 200
1126
        assert expected == response.json()
1127
1128
    async def test_get_specific_schedule_from_mongodb(self):
1129
        """Test get schedules from a circuit."""
1130
        self._add_mongodb_schedule_data(
1131 1
            self.napp.mongo_controller.get_circuits
1132 1
        )
1133 1
1134 1
        requested_circuit_id = "bb:bb:bb"
1135 1
        evc = self.napp.mongo_controller.get_circuits()
1136
        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 1
1140 1
        # Call URL
1141 1
        response = await self.api_client.get(url)
1142 1
1143 1
        # Expected JSON data from response
1144
        expected = [
1145
            {"action": "create", "frequency": "1 * * * *", "id": "3"},
1146
            {"action": "remove", "frequency": "2 * * * *", "id": "4"},
1147
        ]
1148
1149
        assert response.status_code == 200
1150
        assert expected == response.json()["circuit_scheduler"]
1151
1152
    async def test_get_specific_schedules_from_mongodb_not_found(self):
1153 1
        """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 1
1158 1
        # Call URL
1159
        response = await self.api_client.get(url)
1160 1
1161
        expected = "circuit_id blah not found"
1162
        # Assert response not found
1163
        assert response.status_code == 404
1164 1
        assert expected == response.json()["description"]
1165 1
1166
    def _uni_from_dict_side_effect(self, uni_dict):
1167 1
        interface_id = uni_dict.get("interface_id")
1168
        tag_dict = uni_dict.get("tag")
1169
        interface = Interface(interface_id, "0", MagicMock(id="1"))
1170
        return UNI(interface, tag_dict)
1171
1172
    @patch("apscheduler.schedulers.background.BackgroundScheduler.add_job")
1173
    @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
    @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 1
        self,
1180 1
        validate_mock,
1181 1
        evc_as_dict_mock,
1182 1
        mongo_controller_upsert_mock,
1183
        uni_from_dict_mock,
1184
        sched_add_mock,
1185 1
        scheduler_add_job_mock
1186
    ):
1187
        """Test create a circuit schedule."""
1188
        self.napp.controller.loop = asyncio.get_running_loop()
1189
        validate_mock.return_value = True
1190
        mongo_controller_upsert_mock.return_value = True
1191
        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 1
        )
1198 1
1199 1
        requested_id = "bb:bb:bb"
1200 1
        url = f"{self.base_endpoint}/v2/evc/schedule/"
1201
1202
        payload = {
1203 1
            "circuit_id": requested_id,
1204
            "schedule": {"frequency": "1 * * * *", "action": "create"},
1205
            "metadata": {"metadata1": "test_data"},
1206
        }
1207
1208
        # Call URL
1209
        response = await self.api_client.post(url, json=payload)
1210
        response_json = response.json()
1211
1212
        assert response.status_code == 201
1213
        scheduler_add_job_mock.assert_called_once()
1214
        mongo_controller_upsert_mock.assert_called_once()
1215
        assert payload["schedule"]["frequency"] == response_json["frequency"]
1216
        assert payload["schedule"]["action"] == response_json["action"]
1217
        assert response_json["id"] is not None
1218
1219
        # Case 2: there is no schedule
1220
        payload = {
1221
              "circuit_id": "cc:cc:cc",
1222
              "schedule": {
1223
                "frequency": "1 * * * *",
1224
                "action": "create"
1225
              }
1226
            }
1227
        response = await self.api_client.post(url, json=payload)
1228
        assert response.status_code == 201
1229
1230
    async def test_create_schedule_invalid_request(self):
1231
        """Test create schedule API with invalid request."""
1232
        self.napp.controller.loop = asyncio.get_running_loop()
1233
        evc1 = MagicMock()
1234
        self.napp.circuits = {'bb:bb:bb': evc1}
1235
        url = f'{self.base_endpoint}/v2/evc/schedule/'
1236
1237
        # case 1: empty post
1238
        response = await self.api_client.post(url, json={})
1239
        assert response.status_code == 400
1240
1241
        # case 2: not a dictionary
1242
        payload = []
1243 1
        response = await self.api_client.post(url, json=payload)
1244 1
        assert response.status_code == 400
1245 1
1246 1
        # case 3: missing circuit id
1247 1
        payload = {
1248 1
            "schedule": {
1249 1
                "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 1
        }
1260 1
        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
    @patch('apscheduler.schedulers.background.BackgroundScheduler.remove_job')
1279
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1280
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1281
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1282
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1283
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1284 1
    async def test_update_schedule(
1285 1
        self,
1286 1
        validate_mock,
1287 1
        evc_as_dict_mock,
1288 1
        mongo_controller_upsert_mock,
1289 1
        uni_from_dict_mock,
1290 1
        sched_add_mock,
1291
        scheduler_remove_job_mock
1292 1
    ):
1293 1
        """Test create a circuit schedule."""
1294
        self.napp.controller.loop = asyncio.get_running_loop()
1295 1
        mongo_payload_1 = {
1296
            "circuits": {
1297
                "aa:aa:aa": {
1298 1
                    "id": "aa:aa:aa",
1299 1
                    "name": "my evc1",
1300
                    "uni_a": {
1301 1
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1302 1
                        "tag": {"tag_type": 'vlan', "value": 80},
1303 1
                    },
1304 1
                    "uni_z": {
1305 1
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1306 1
                        "tag": {"tag_type": 'vlan', "value": 1},
1307
                    },
1308 1
                    "circuit_scheduler": [
1309 1
                        {
1310
                            "id": "1",
1311
                            "frequency": "* * * * *",
1312
                            "action": "create"
1313 1
                        }
1314 1
                    ],
1315 1
                }
1316
            }
1317 1
        }
1318
1319 1
        validate_mock.return_value = True
1320
        mongo_controller_upsert_mock.return_value = True
1321
        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 1
1327 1
        requested_schedule_id = "1"
1328
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1329 1
1330
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1331
1332
        # Call URL
1333
        response = await self.api_client.patch(url, json=payload)
1334
        response_json = response.json()
1335
1336
        assert response.status_code == 200
1337 1
        scheduler_remove_job_mock.assert_called_once()
1338
        mongo_controller_upsert_mock.assert_called_once()
1339
        assert payload["frequency"] == response_json["frequency"]
1340
        assert payload["action"] == response_json["action"]
1341
        assert response_json["id"] is not None
1342
1343
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1344
    async def test_update_no_schedule(
1345
        self, find_evc_by_schedule_id_mock
1346
    ):
1347
        """Test update a circuit schedule."""
1348
        self.napp.controller.loop = asyncio.get_running_loop()
1349
        url = f"{self.base_endpoint}/v2/evc/schedule/1"
1350
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1351
1352
        find_evc_by_schedule_id_mock.return_value = None, None
1353
1354
        response = await self.api_client.patch(url, json=payload)
1355
        assert response.status_code == 404
1356
1357
    @patch("apscheduler.schedulers.background.BackgroundScheduler.remove_job")
1358
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1359
    @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 1
        """Test create a circuit schedule."""
1364 1
        (
1365 1
            validate_mock,
1366
            evc_as_dict_mock,
1367 1
            mongo_controller_upsert_mock,
1368 1
            uni_from_dict_mock,
1369
            scheduler_remove_job_mock,
1370
        ) = args
1371 1
1372
        mongo_payload_1 = {
1373 1
            "circuits": {
1374 1
                "2": {
1375 1
                    "id": "2",
1376 1
                    "name": "my evc1",
1377
                    "uni_a": {
1378 1
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1379 1
                        "tag": {"tag_type": 'vlan', "value": 80},
1380
                    },
1381 1
                    "uni_z": {
1382 1
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1383 1
                        "tag": {"tag_type": 'vlan', "value": 1},
1384
                    },
1385
                    "circuit_scheduler": [
1386 1
                        {
1387
                            "id": "1",
1388 1
                            "frequency": "* * * * *",
1389 1
                            "action": "create"
1390
                        }
1391 1
                    ],
1392 1
                }
1393 1
            }
1394 1
        }
1395
        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
        evc_as_dict_mock.return_value = {}
1399 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1400
        scheduler_remove_job_mock.return_value = True
1401 1
1402 1
        requested_schedule_id = "1"
1403 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1404 1
1405
        # Call URL
1406 1
        response = await self.api_client.delete(url)
1407 1
1408 1
        assert response.status_code == 200
1409
        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 1
1413
    @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 1
        """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 1
                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 1
1431 1
        for evc, exp_level in zip(evcs_by_level, expected_levels):
1432 1
            assert evc.service_level == exp_level
1433
1434
        evcs = {i: MagicMock(service_level=1, creation_time=i)
1435
                for i in reversed(range(2))}
1436
        self.napp.circuits = evcs
1437
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1438
        for i in range(2):
1439
            assert evcs_by_level[i].creation_time == i
1440
1441
        self.napp.circuits[1].is_enabled = lambda: False
1442
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1443
        assert len(evcs_by_level) == 1
1444
1445
        self.napp.circuits[1].is_enabled = lambda: False
1446
        evcs_by_level = self.napp.get_evcs_by_svc_level(enable_filter=False)
1447 1
        assert len(evcs_by_level) == 2
1448 1
1449 1
    async def test_get_circuit_not_found(self):
1450 1
        """Test /v2/evc/<circuit_id> 404."""
1451 1
        self.napp.mongo_controller.get_circuit.return_value = None
1452
        url = f'{self.base_endpoint}/v2/evc/1234'
1453
        response = await self.api_client.get(url)
1454
        assert response.status_code == 404
1455 1
1456
    @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
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1461 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1462
    @patch('kytos.core.Controller.get_interface_by_id')
1463
    @patch('napps.kytos.mef_eline.models.path.Path.is_valid')
1464
    @patch('napps.kytos.mef_eline.models.evc.EVCDeploy.deploy')
1465
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1466
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1467
    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
        self.napp.controller.loop = asyncio.get_running_loop()
1483
        mock_use_uni_tags.return_value = True
1484
        evc_deploy.return_value = True
1485
        interface_by_id_mock.return_value = get_uni_mocked().interface
1486
        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
        uni_from_dict_mock.side_effect = 2 * unis
1491
1492
        response = MagicMock()
1493
        response.status_code = 201
1494 1
        httpx_mock.return_value = response
1495 1
1496
        payloads = [
1497
            {
1498
                "name": "my evc1",
1499 1
                "uni_a": {
1500
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1501 1
                    "tag": {"tag_type": 'vlan', "value": 80},
1502 1
                },
1503 1
                "uni_z": {
1504 1
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1505 1
                    "tag": {"tag_type": 'vlan', "value": 1},
1506
                },
1507
                "dynamic_backup_path": True,
1508
            },
1509
            {
1510 1
                "primary_path": [
1511
                    {
1512 1
                        "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1513 1
                        "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1514 1
                    }
1515
                ]
1516
            },
1517
            {
1518 1
                "sb_priority": 3
1519 1
            },
1520
            {
1521 1
                # It works only with 'enabled' and not with 'enable'
1522 1
                "enabled": True
1523 1
            },
1524
            {
1525
                "sb_priority": 100
1526
            }
1527 1
        ]
1528 1
1529
        evc_as_dict_mock.return_value = payloads[0]
1530 1
        response = await self.api_client.post(
1531 1
            f"{self.base_endpoint}/v2/evc/",
1532
            json=payloads[0],
1533
        )
1534
        assert 201 == response.status_code
1535
1536
        evc_deploy.reset_mock()
1537
        evc_as_dict_mock.return_value = payloads[1]
1538
        current_data = response.json()
1539
        circuit_id = current_data["circuit_id"]
1540
        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
        assert 200 == response.status_code
1546
1547
        evc_deploy.reset_mock()
1548
        evc_as_dict_mock.return_value = payloads[2]
1549
        response = await self.api_client.patch(
1550
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1551
            json=payloads[2],
1552
        )
1553
        evc_deploy.assert_not_called()
1554 1
        assert 200 == response.status_code
1555 1
1556
        evc_deploy.reset_mock()
1557 1
        evc_as_dict_mock.return_value = payloads[3]
1558 1
        response = await self.api_client.patch(
1559 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1560 1
            json=payloads[3],
1561 1
        )
1562 1
        evc_deploy.assert_called_once()
1563 1
        assert 200 == response.status_code
1564 1
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 1
        expected_data = "circuit_id 1234 not found"
1580 1
        assert current_data["description"] == expected_data
1581 1
        assert 404 == response.status_code
1582 1
1583 1
        self.napp.circuits[circuit_id]._active = False
1584 1
        evc_deploy.reset_mock()
1585 1
        response = await self.api_client.patch(
1586 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1587 1
            json=payloads[4]
1588 1
        )
1589 1
        assert 200 == response.status_code
1590 1
        evc_deploy.assert_called_once()
1591 1
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
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1595 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1596
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1597
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1598
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1599
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1600
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1601
    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 1
        evc_deploy_mock,
1609
        mock_use_uni_tags,
1610
        mock_tags_equal,
1611
        mock_check_duplicate
1612 1
    ):
1613 1
        """Test update a circuit circuit."""
1614
        self.napp.controller.loop = asyncio.get_running_loop()
1615
        validate_mock.return_value = True
1616
        mongo_controller_upsert_mock.return_value = True
1617 1
        sched_add_mock.return_value = True
1618
        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
        uni2 = create_autospec(UNI)
1624
        uni1.interface = create_autospec(Interface)
1625
        uni2.interface = create_autospec(Interface)
1626
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1627
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1628
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1629
1630 1
        payload1 = {
1631 1
            "name": "my evc1",
1632 1
            "uni_a": {
1633 1
                "interface_id": "00:00:00:00:00:00:00:01:1",
1634 1
                "tag": {"tag_type": 'vlan', "value": 80},
1635 1
            },
1636 1
            "uni_z": {
1637 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
1638 1
                "tag": {"tag_type": 'vlan', "value": 1},
1639 1
            },
1640 1
            "dynamic_backup_path": True,
1641 1
        }
1642
1643
        payload2 = {
1644
            "dynamic_backup_path": False,
1645
        }
1646
1647
        evc_as_dict_mock.return_value = payload1
1648
        response = await self.api_client.post(
1649
            f"{self.base_endpoint}/v2/evc/",
1650
            json=payload1
1651
        )
1652
        assert 201 == response.status_code
1653
1654
        evc_as_dict_mock.return_value = payload2
1655
        current_data = response.json()
1656 1
        circuit_id = current_data["circuit_id"]
1657 1
        response = await self.api_client.patch(
1658 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1659 1
            json=payload2
1660 1
        )
1661 1
        current_data = response.json()
1662 1
        assert 400 == response.status_code
1663 1
        assert "must have a primary path or" in current_data["description"]
1664 1
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
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1674 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1675
    @patch("napps.kytos.mef_eline.models.path.Path.is_valid")
1676
    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 1
        mock_tags_equal,
1688
        mock_check_duplicate
1689
    ):
1690
        """Test update a circuit circuit."""
1691
        self.napp.controller.loop = asyncio.get_running_loop()
1692
        is_valid_mock.side_effect = InvalidPath("error")
1693
        validate_mock.return_value = True
1694
        mongo_controller_upsert_mock.return_value = True
1695
        sched_add_mock.return_value = True
1696 1
        evc_deploy_mock.return_value = True
1697 1
        mock_use_uni_tags.return_value = True
1698
        link_from_dict_mock.return_value = 1
1699
        mock_tags_equal.return_value = True
1700
        mock_check_duplicate.return_value = True
1701 1
        uni1 = create_autospec(UNI)
1702
        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
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1708
1709
        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 1
            "uni_z": {
1716
                "interface_id": "00:00:00:00:00:00:00:02:2",
1717 1
                "tag": {"tag_type": 'vlan', "value": 1},
1718 1
            },
1719
            "dynamic_backup_path": True,
1720
        }
1721
1722 1
        payload2 = {
1723 1
            "primary_path": [
1724
                {
1725 1
                    "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 1
            ]
1729 1
        }
1730 1
1731
        evc_as_dict_mock.return_value = payload1
1732
        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 1
1738
        evc_as_dict_mock.return_value = payload2
1739 1
        current_data = response.json()
1740 1
        circuit_id = current_data["circuit_id"]
1741
        response = await self.api_client.patch(
1742 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1743 1
            json=payload2,
1744
        )
1745 1
        current_data = response.json()
1746
        expected_data = "primary_path is not a valid path: error"
1747 1
        assert 400 == response.status_code
1748 1
        assert current_data["description"] == expected_data
1749
1750
    def test_link_from_dict_non_existent_intf(self):
1751 1
        """Test _link_from_dict non existent intf."""
1752 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1753
        link_dict = {
1754 1
            "endpoint_a": {"id": "a"},
1755 1
            "endpoint_b": {"id": "b"}
1756 1
        }
1757 1
        with pytest.raises(ValueError):
1758 1
            self.napp._link_from_dict(link_dict, "current_path")
1759 1
1760 1
    def test_link_from_dict_vlan_metadata(self):
1761 1
        """Test that link_from_dict only accepts vlans for current_path
1762 1
         and failover_path."""
1763
        intf = MagicMock(id="01:1")
1764
        self.napp.controller.get_interface_by_id = MagicMock(return_value=intf)
1765
        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
        link = self.napp._link_from_dict(link_dict, "current_path")
1772
        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 1
1777 1
        link = self.napp._link_from_dict(link_dict, "primary_path")
1778 1
        assert link.metadata.get('s_vlan', None) is None
1779 1
1780 1
    def test_uni_from_dict_non_existent_intf(self):
1781 1
        """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 1
            "interface_id": "aaa",
1785 1
        }
1786 1
        with pytest.raises(ValueError):
1787 1
            self.napp._uni_from_dict(uni_dict)
1788 1
1789 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
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1792
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1793
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1794
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1795
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1796
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1797
    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 1
        evc_deploy_mock,
1804
        mock_use_uni_tags,
1805 1
        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
        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
        mock_tags_equal.return_value = True
1815
        mock_check_duplicate.return_value = True
1816
        uni1 = create_autospec(UNI)
1817
        uni2 = create_autospec(UNI)
1818
        uni1.interface = create_autospec(Interface)
1819
        uni2.interface = create_autospec(Interface)
1820 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1821
        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
        payload1 = {
1826
            "name": "my evc1",
1827
            "uni_a": {
1828
                "interface_id": "00:00:00:00:00:00:00:01:1",
1829 1
                "tag": {"tag_type": 'vlan', "value": 80},
1830 1
            },
1831 1
            "uni_z": {
1832 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
1833 1
                "tag": {"tag_type": 'vlan', "value": 1},
1834 1
            },
1835 1
            "dynamic_backup_path": True,
1836 1
        }
1837 1
1838 1
        payload2 = {"dynamic_backup_path": False}
1839 1
1840 1
        response = await self.api_client.post(
1841
            f"{self.base_endpoint}/v2/evc/",
1842
            json=payload1,
1843
        )
1844
        assert 201 == response.status_code
1845
1846
        current_data = response.json()
1847
        circuit_id = current_data["circuit_id"]
1848
        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 1
        """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 1
        current_data = response.json()
1860 1
        expected_data = "circuit_id 123 not found"
1861 1
        assert current_data["description"] == expected_data
1862 1
        assert 404 == response.status_code
1863 1
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
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1871 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1872
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1873
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1874
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1875
    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 1
        mock_use_uni,
1885 1
        mock_remove_tags,
1886
        mock_tags_equal,
1887
        mock_check_duplicate
1888
    ):
1889 1
        """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
        evc_deploy_mock.return_value = True
1895 1
        mock_use_uni.return_value = True
1896
        mock_tags_equal.return_value = True
1897
        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
        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
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1905
1906
        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 1
            "uni_z": {
1913 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
1914
                "tag": {"tag_type": 'vlan', "value": 1},
1915 1
            },
1916 1
            "dynamic_backup_path": True,
1917 1
        }
1918 1
1919 1
        evc_as_dict_mock.return_value = payload1
1920
        response = await self.api_client.post(
1921
            f"{self.base_endpoint}/v2/evc/",
1922 1
            json=payload1
1923 1
        )
1924 1
        assert 201 == response.status_code
1925 1
        assert len(self.napp.circuits) == 1
1926
        current_data = response.json()
1927
        circuit_id = current_data["circuit_id"]
1928 1
        self.napp.circuits[circuit_id].archive()
1929
1930
        response = await self.api_client.delete(
1931 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1932 1
        )
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
        assert len(self.napp.circuits) == 0
1937 1
1938
        response = await self.api_client.delete(
1939 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1940 1
        )
1941 1
        current_data = response.json()
1942
        expected_data = f"circuit_id {circuit_id} not found"
1943
        assert current_data["description"] == expected_data
1944 1
        assert 404 == response.status_code
1945 1
        assert len(self.napp.circuits) == 0
1946 1
1947 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1948 1
    async def test_delete_circuit(self, emit_event_mock):
1949 1
        """Test delete_circuit"""
1950 1
        evc = MagicMock()
1951 1
        evc.archived = False
1952
        circuit_id = '1'
1953 1
        self.napp.circuits[circuit_id] = evc
1954
        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
        evc.remove_current_flows.assert_called_once_with(
1961 1
            sync=False
1962 1
        )
1963 1
        evc.remove_failover_flows.assert_called_once_with(
1964
            sync=False
1965 1
        )
1966
        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
        assert emit_event_mock.call_count == 1
1971 1
1972 1
    def test_handle_link_up(self):
1973 1
        """Test handle_link_up method."""
1974
        evc_mock = create_autospec(EVC)
1975 1
        evc_mock.service_level, evc_mock.creation_time = 0, 1
1976
        evc_mock.is_enabled = MagicMock(side_effect=[
1977 1
            True, False, True, True, True
1978 1
        ])
1979 1
        evc_mock.lock = MagicMock()
1980
        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
        self.napp.handle_link_up(event)
1985 1
        assert evc_mock.handle_link_up.call_count == 2
1986
        evc_mock.handle_link_up.assert_called_with("abc")
1987 1
1988
    def test_handle_link_down(
1989 1
        self
1990
    ):
1991
        """Test handle_link_down method."""
1992
        evc1 = MagicMock(id="1")
1993
        evc1.is_affected_by_link.return_value = True
1994
        evc1.is_failover_path_affected_by_link.return_value = True
1995
1996
        evc2 = MagicMock(id="2")
1997
        evc2.is_affected_by_link.return_value = True
1998 1
        evc2.failover_path = Path([])
1999
2000 1
        default_undeploy = [evc1, evc2]
2001 1
2002
        evc3 = MagicMock(id="3")
2003 1
        evc3.is_affected_by_link.return_value = True
2004
        evc3.is_failover_path_affected_by_link.return_value = False
2005
2006 1
        evc4 = MagicMock(id="4")
2007
        evc4.is_affected_by_link.return_value = True
2008 1
        evc4.is_failover_path_affected_by_link.return_value = False
2009 1
2010
        default_swap_to_failover = [evc3, evc4]
2011 1
2012
        evc5 = MagicMock(id="5")
2013
        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
        evc6.is_failover_path_affected_by_link.return_value = True
2019 1
2020
        default_clear_failover = [evc5, evc6]
2021
2022 1
        self.napp.get_evcs_by_svc_level = MagicMock()
2023 1
2024
        self.napp.get_evcs_by_svc_level.return_value = [
2025 1
            evc1,
2026
            evc2,
2027 1
            evc3,
2028
            evc4,
2029
            evc5,
2030
            evc6,
2031 1
        ]
2032
2033
        self.napp.execute_swap_to_failover = MagicMock()
2034
2035 1
        swap_to_failover_success = [evc3]
2036
        swap_to_failover_failure = [evc4]
2037
2038
        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
        clear_failover_success = [evc5, evc3]
2044
        clear_failover_failure = [evc6]
2045
2046
        self.napp.execute_clear_failover.return_value =\
2047
            clear_failover_success, clear_failover_failure
2048
2049 1
        self.napp.execute_undeploy = MagicMock()
2050 1
2051 1
        undeploy_success = [evc1, evc4, evc6]
2052
        undeploy_failure = [evc2]
2053
2054
        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 1
2060 1
        self.napp.handle_link_down(event)
2061 1
2062 1
        self.napp.execute_swap_to_failover.assert_called_with(
2063
            default_swap_to_failover
2064 1
        )
2065
2066
        self.napp.execute_clear_failover.assert_called_with(
2067
            [*default_clear_failover, *swap_to_failover_success]
2068
        )
2069 1
2070
        self.napp.execute_undeploy.assert_called_with([
2071
            *default_undeploy,
2072
            *swap_to_failover_failure,
2073 1
            *clear_failover_failure
2074
        ])
2075 1
2076 1
        self.napp.mongo_controller.update_evcs.assert_called_with([
2077
            evc3.as_dict(),
2078 1
            evc5.as_dict(),
2079
            evc1.as_dict(),
2080
            evc4.as_dict(),
2081
            evc6.as_dict(),
2082
        ])
2083 1
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
    @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
        evc1.current_path = bad_path
2096
        evc1.failover_path = good_path
2097
        evc2 = MagicMock(id="2")
2098
2099
        self.napp.prepare_swap_to_failover_flow = {
2100 1
            evc1: {"1": ["Flow1"]},
2101 1
            evc2: None
2102 1
        }.get
2103 1
2104 1
        self.napp.prepare_swap_to_failover_event = {
2105 1
            evc1: "FailoverEvent1",
2106
        }.get
2107 1
2108
        success, failure = self.napp.execute_swap_to_failover([evc1, evc2])
2109
2110
        assert success == [evc1]
2111
        assert failure == [evc2]
2112 1
2113
        send_flow_mods_mock.assert_called_with(
2114
            {"1": ["Flow1"]},
2115
            "install"
2116 1
        )
2117
2118
        assert evc1.current_path == good_path
2119
        assert evc1.failover_path == bad_path
2120 1
2121
        emit_main_mock.assert_called_with(
2122 1
            self.napp.controller,
2123 1
            "failover_link_down",
2124
            content={"1": "FailoverEvent1"}
2125 1
        )
2126
2127 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
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2129
    def test_execute_swap_to_failover_exception(
2130 1
        self,
2131 1
        send_flow_mods_mock: MagicMock,
2132
        emit_main_mock: MagicMock,
2133 1
    ):
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
        evc1.current_path = bad_path
2139
        evc1.failover_path = good_path
2140
        evc2 = MagicMock(id="2")
2141
2142
        self.napp.prepare_swap_to_failover_flow = {
2143 1
            evc1: {"1": ["Flow1"]},
2144 1
            evc2: None
2145 1
        }.get
2146 1
2147 1
        self.napp.prepare_swap_to_failover_event = {
2148 1
            evc1: "FailoverEvent1",
2149
        }.get
2150 1
2151
        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
        assert success == []
2158
        assert failure == [evc1, evc2]
2159 1
2160
        send_flow_mods_mock.assert_called_with(
2161 1
            {"1": ["Flow1"]},
2162 1
            "install"
2163
        )
2164 1
2165
        assert evc1.current_path == bad_path
2166
        assert evc1.failover_path == good_path
2167
2168
        emit_main_mock.assert_not_called()
2169 1
2170 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2171
    @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 1
    ):
2177
        """Test execute_clear_failover method."""
2178
        evc1 = MagicMock(id="1")
2179
        good_path = MagicMock(id="GoodPath")
2180
        bad_path = MagicMock(id="BadPath")
2181
        evc1.current_path = good_path
2182 1
        evc1.failover_path = bad_path
2183 1
        evc2 = MagicMock(id="2")
2184 1
2185
        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 1
            evc1: "FailoverEvent1",
2192 1
        }.get
2193 1
2194 1
        success, failure = self.napp.execute_clear_failover([evc1, evc2])
2195 1
2196
        assert success == [evc1]
2197 1
        assert failure == [evc2]
2198
2199
        send_flow_mods_mock.assert_called_with(
2200
            {"1": ["Flow1"]},
2201
            "delete"
2202 1
        )
2203
2204
        assert evc1.current_path == good_path
2205
        assert not evc1.failover_path
2206 1
2207
        bad_path.make_vlans_available.assert_called_once_with(
2208
            self.napp.controller
2209
        )
2210 1
2211
        emit_main_mock.assert_called_with(
2212 1
            self.napp.controller,
2213 1
            "failover_old_path",
2214
            content={"1": "FailoverEvent1"}
2215 1
        )
2216
2217
    @patch("napps.kytos.mef_eline.main.emit_event")
2218
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2219
    def test_execute_clear_failover_exception(
2220 1
        self,
2221 1
        send_flow_mods_mock: MagicMock,
2222
        emit_main_mock: MagicMock,
2223 1
    ):
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
        evc1.current_path = good_path
2229
        evc1.failover_path = bad_path
2230
        evc2 = MagicMock(id="2")
2231
2232
        self.napp.prepare_clear_failover_flow = {
2233 1
            evc1: {"1": ["Flow1"]},
2234 1
            evc2: None
2235 1
        }.get
2236 1
2237 1
        self.napp.prepare_clear_failover_event = {
2238 1
            evc1: "FailoverEvent1",
2239
        }.get
2240 1
2241
        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 1
2260
    @patch("napps.kytos.mef_eline.main.emit_event")
2261 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2262
    def test_execute_undeploy(
2263
        self,
2264 1
        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
        bad_path2 = MagicMock(id="BadPath")
2271 1
        evc1.current_path = bad_path1
2272
        evc1.failover_path = bad_path2
2273
        evc2 = MagicMock(id="2")
2274
2275
        self.napp.prepare_undeploy_flow = {
2276
            evc1: {"1": ["Flow1"]},
2277 1
            evc2: None
2278 1
        }.get
2279 1
2280
        success, failure = self.napp.execute_undeploy([evc1, evc2])
2281
2282
        assert success == [evc1]
2283
        assert failure == [evc2]
2284
2285 1
        send_flow_mods_mock.assert_called_with(
2286 1
            {"1": ["Flow1"]},
2287 1
            "delete"
2288 1
        )
2289 1
2290 1
        assert not evc1.current_path
2291
        assert not evc1.failover_path
2292 1
2293
        assert evc2.current_path
2294
        assert evc2.failover_path
2295
2296
        bad_path1.make_vlans_available.assert_called_once_with(
2297 1
            self.napp.controller
2298
        )
2299
        bad_path2.make_vlans_available.assert_called_once_with(
2300
            self.napp.controller
2301 1
        )
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 1
2312 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2313
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2314 1
    def test_execute_undeploy_exception(
2315 1
        self,
2316
        send_flow_mods_mock: MagicMock,
2317 1
        emit_main_mock: MagicMock,
2318 1
    ):
2319
        """Test execute_undeploy method method when an exception occurs."""
2320 1
        evc1 = MagicMock(id="1")
2321 1
        bad_path1 = MagicMock(id="GoodPath")
2322
        bad_path2 = MagicMock(id="BadPath")
2323 1
        evc1.current_path = bad_path1
2324
        evc1.failover_path = bad_path2
2325 1
        evc2 = MagicMock(id="2")
2326 1
2327
        self.napp.prepare_undeploy_flow = {
2328 1
            evc1: {"1": ["Flow1"]},
2329 1
            evc2: None
2330
        }.get
2331
2332
        send_flow_mods_mock.side_effect = FlowModException(
2333
            "Flowmod failed to send"
2334
        )
2335
2336
        success, failure = self.napp.execute_undeploy([evc1, evc2])
2337 1
2338 1
        assert success == []
2339 1
        assert failure == [evc1, evc2]
2340
2341
        send_flow_mods_mock.assert_called_with(
2342
            {"1": ["Flow1"]},
2343
            "delete"
2344
        )
2345
2346
        assert evc1.current_path
2347 1
        assert evc1.failover_path
2348 1
2349 1
        assert evc2.current_path
2350
        assert evc2.failover_path
2351 1
2352
        bad_path1.make_vlans_available.assert_not_called()
2353
        bad_path2.make_vlans_available.assert_not_called()
2354
2355 1
        evc1.deactivate.assert_not_called()
2356 1
        evc2.deactivate.assert_not_called()
2357 1
2358 1
        emit_main_mock.assert_not_called()
2359 1
2360
    @patch("napps.kytos.mef_eline.main.emit_event")
2361
    def test_handle_evc_affected_by_link_down(self, emit_event_mock):
2362
        """Test handle_evc_affected_by_link_down method."""
2363
        uni = create_autospec(UNI)
2364
        evc1 = MagicMock(
2365
            id="1",
2366
            metadata="data_mocked",
2367
            _active="true",
2368
            _enabled="false",
2369
            uni_a=uni,
2370
            uni_z=uni,
2371
        )
2372 1
        evc1.name = "name_mocked"
2373 1
        evc1.handle_link_down.return_value = True
2374 1
        evc2 = MagicMock(
2375
            id="2",
2376
            metadata="mocked_data",
2377
            _active="false",
2378
            _enabled="true",
2379
            uni_a=uni,
2380
            uni_z=uni,
2381
        )
2382
        evc2.name = "mocked_name"
2383
        evc2.handle_link_down.return_value = False
2384
        self.napp.circuits = {"1": evc1, "2": evc2}
2385
2386
        event = KytosEvent(name="e1", content={
2387 1
            "evc_id": "3",
2388
            "link": MagicMock(),
2389 1
        })
2390 1
        self.napp.handle_evc_affected_by_link_down(event)
2391 1
        emit_event_mock.assert_not_called()
2392 1
        event.content["evc_id"] = "1"
2393 1
        self.napp.handle_evc_affected_by_link_down(event)
2394
        emit_event_mock.assert_called_with(
2395 1
            self.napp.controller, "redeployed_link_down", content={
2396 1
                "id": "1",
2397
                "evc_id": "1",
2398
                "name": "name_mocked",
2399
                "metadata": "data_mocked",
2400
                "active": "true",
2401 1
                "enabled": "false",
2402 1
                "uni_a": uni.as_dict(),
2403
                "uni_z": uni.as_dict(),
2404 1
            }
2405
        )
2406 1
2407 1
        event.content["evc_id"] = "2"
2408 1
        self.napp.handle_evc_affected_by_link_down(event)
2409
        emit_event_mock.assert_called_with(
2410
            self.napp.controller, "error_redeploy_link_down", content={
2411
                "evc_id": "2",
2412
                "id": "2",
2413
                "name": "mocked_name",
2414
                "metadata": "mocked_data",
2415
                "active": "false",
2416
                "enabled": "true",
2417 1
                "uni_a": uni.as_dict(),
2418
                "uni_z": uni.as_dict(),
2419 1
            }
2420 1
        )
2421
2422
    async def test_add_metadata(self):
2423
        """Test method to add metadata"""
2424
        self.napp.controller.loop = asyncio.get_running_loop()
2425
        evc_mock = create_autospec(EVC)
2426
        evc_mock.metadata = {}
2427 1
        evc_mock.id = 1234
2428
        self.napp.circuits = {"1234": evc_mock}
2429 1
2430 1
        payload = {"metadata1": 1, "metadata2": 2}
2431 1
        response = await self.api_client.post(
2432
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2433
            json=payload
2434
        )
2435
2436
        assert response.status_code == 201
2437
        evc_mock.extend_metadata.assert_called_with(payload)
2438
2439 1
    async def test_add_metadata_malformed_json(self):
2440
        """Test method to add metadata with a malformed json"""
2441 1
        self.napp.controller.loop = asyncio.get_running_loop()
2442 1
        payload = b'{"metadata1": 1, "metadata2": 2,}'
2443 1
        response = await self.api_client.post(
2444
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2445
            content=payload,
2446
            headers={"Content-Type": "application/json"}
2447
        )
2448
2449
        assert response.status_code == 400
2450
        assert "body contains invalid API" in response.json()["description"]
2451 1
2452
    async def test_add_metadata_no_body(self):
2453 1
        """Test method to add metadata with no body"""
2454 1
        self.napp.controller.loop = asyncio.get_running_loop()
2455 1
        response = await self.api_client.post(
2456 1
            f"{self.base_endpoint}/v2/evc/1234/metadata"
2457
        )
2458 1
        assert response.status_code == 400
2459
        assert response.json()["description"] == \
2460
            "Missing required request body"
2461 1
2462 1
    async def test_add_metadata_no_evc(self):
2463
        """Test method to add metadata with no evc"""
2464 1
        self.napp.controller.loop = asyncio.get_running_loop()
2465
        payload = {"metadata1": 1, "metadata2": 2}
2466 1
        response = await self.api_client.post(
2467 1
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2468 1
            json=payload,
2469 1
        )
2470
        assert response.status_code == 404
2471 1
        assert response.json()["description"] == \
2472
            "circuit_id 1234 not found."
2473
2474 1
    async def test_add_metadata_wrong_content_type(self):
2475
        """Test method to add metadata with wrong content type"""
2476 1
        self.napp.controller.loop = asyncio.get_running_loop()
2477
        payload = {"metadata1": 1, "metadata2": 2}
2478 1
        response = await self.api_client.post(
2479
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2480
            data=payload,
2481
            headers={"Content-Type": "application/xml"}
2482
        )
2483
        assert response.status_code == 415
2484
        assert "application/xml" in response.json()["description"]
2485 1
2486 1
    async def test_get_metadata(self):
2487
        """Test method to get metadata"""
2488 1
        evc_mock = create_autospec(EVC)
2489
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2490
        evc_mock.id = 1234
2491
        self.napp.circuits = {"1234": evc_mock}
2492
2493
        response = await self.api_client.get(
2494
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2495
        )
2496 1
        assert response.status_code == 200
2497 1
        assert response.json() == {"metadata": evc_mock.metadata}
2498 1
2499 1
    async def test_delete_metadata(self):
2500 1
        """Test method to delete metadata"""
2501 1
        evc_mock = create_autospec(EVC)
2502 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2503 1
        evc_mock.id = 1234
2504 1
        self.napp.circuits = {"1234": evc_mock}
2505 1
2506
        response = await self.api_client.delete(
2507 1
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2508 1
        )
2509
        assert response.status_code == 200
2510
2511
    async def test_delete_metadata_no_evc(self):
2512 1
        """Test method to delete metadata with no evc"""
2513 1
        response = await self.api_client.delete(
2514 1
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2515
        )
2516
        assert response.status_code == 404
2517 1
        assert response.json()["description"] == \
2518 1
            "circuit_id 1234 not found."
2519
2520
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
2521 1
    def test_load_all_evcs(self, load_evc_mock):
2522 1
        """Test load_evcs method"""
2523 1
        mock_circuits = {
2524 1
            'circuits': {
2525 1
                1: 'circuit_1',
2526
                2: 'circuit_2',
2527
                3: 'circuit_3',
2528 1
                4: 'circuit_4'
2529 1
            }
2530 1
        }
2531
        self.napp.mongo_controller.get_circuits.return_value = mock_circuits
2532 1
        self.napp.circuits = {2: 'circuit_2', 3: 'circuit_3'}
2533 1
        self.napp.load_all_evcs()
2534 1
        load_evc_mock.assert_has_calls([call('circuit_1'), call('circuit_4')])
2535 1
        assert self.napp.controller.buffers.app.put.call_count > 1
2536
        call_args = self.napp.controller.buffers.app.put.call_args[0]
2537 1
        assert call_args[0].name == "kytos/mef_eline.evcs_loaded"
2538
        assert dict(call_args[0].content) == mock_circuits["circuits"]
2539 1
        timeout_d = {"timeout": 1}
2540 1
        assert self.napp.controller.buffers.app.put.call_args[1] == timeout_d
2541 1
2542 1
    @patch('napps.kytos.mef_eline.main.Main._evc_from_dict')
2543 1
    def test_load_evc(self, evc_from_dict_mock):
2544 1
        """Test _load_evc method"""
2545 1
        # pylint: disable=protected-access
2546 1
        # case 1: early return with ValueError exception
2547 1
        evc_from_dict_mock.side_effect = ValueError("err")
2548 1
        evc_dict = MagicMock()
2549 1
        assert not self.napp._load_evc(evc_dict)
2550
2551 1
        # case 2: early return with KytosTagError exception
2552
        evc_from_dict_mock.side_effect = KytosTagError("")
2553 1
        assert not self.napp._load_evc(evc_dict)
2554 1
2555 1
        # case 3: archived evc
2556 1
        evc = MagicMock()
2557
        evc.archived = True
2558 1
        evc_from_dict_mock.side_effect = None
2559 1
        evc_from_dict_mock.return_value = evc
2560 1
        assert not self.napp._load_evc(evc_dict)
2561
2562
        # case 4: success creating
2563 1
        evc.archived = False
2564 1
        evc.id = 1
2565 1
        self.napp.sched = MagicMock()
2566
2567
        result = self.napp._load_evc(evc_dict)
2568 1
        assert result == evc
2569 1
        self.napp.sched.add.assert_called_with(evc)
2570 1
        assert self.napp.circuits[1] == evc
2571 1
2572
    def test_handle_flow_mod_error(self):
2573
        """Test handle_flow_mod_error method"""
2574 1
        flow = MagicMock()
2575 1
        flow.cookie = 0xaa00000000000011
2576 1
        event = MagicMock()
2577 1
        event.content = {'flow': flow, 'error_command': 'add'}
2578
        evc = create_autospec(EVC)
2579
        evc.archived = False
2580 1
        evc.remove_current_flows = MagicMock()
2581 1
        evc.lock = MagicMock()
2582 1
        self.napp.circuits = {"00000000000011": evc}
2583 1
        self.napp.handle_flow_mod_error(event)
2584
        evc.remove_current_flows.assert_called_once()
2585 1
2586 1
    def test_handle_flow_mod_error_return(self):
2587
        """Test handle_flow_mod_error method with early return."""
2588
        flow = MagicMock()
2589
        flow.cookie = 0xaa00000000000011
2590 1
        event = MagicMock()
2591
        event.content = {'flow': flow, 'error_command': 'delete'}
2592
2593 1
        evc = create_autospec(EVC)
2594 1
        evc.archived = False
2595
        evc.is_enabled.return_value = True
2596
2597
        # Flow command is not 'add'
2598 1
        self.napp.circuits = {"00000000000011": evc}
2599 1
        self.napp.handle_flow_mod_error(event)
2600
        assert not evc.remove_current_flows.call_count
2601
2602 1
        # EVC is not enabled
2603 1
        event.content["error_command"] = "add"
2604 1
        evc.is_enabled.return_value = False
2605 1
        self.napp.handle_flow_mod_error(event)
2606
        assert not evc.remove_current_flows.call_count
2607
2608 1
        # EVC is archived
2609 1
        evc.is_enabled.return_value = True
2610 1
        evc.archived = True
2611
        self.napp.handle_flow_mod_error(event)
2612
        assert not evc.remove_current_flows.call_count
2613 1
2614 1
        # EVC does not exist in self.circuits
2615 1
        evc.archived = False
2616 1
        self.napp.circuits = {}
2617
        self.napp.handle_flow_mod_error(event)
2618 1
        assert not evc.remove_current_flows.call_count
2619
2620 1
    @patch("kytos.core.Controller.get_interface_by_id")
2621 1
    def test_uni_from_dict(self, _get_interface_by_id_mock):
2622 1
        """Test _uni_from_dict method."""
2623 1
        # pylint: disable=protected-access
2624 1
        # case1: early return on empty dict
2625 1
        assert not self.napp._uni_from_dict(None)
2626 1
2627 1
        # case2: invalid interface raises ValueError
2628 1
        _get_interface_by_id_mock.return_value = None
2629
        uni_dict = {
2630 1
            "interface_id": "00:01:1",
2631
            "tag": {"tag_type": 'vlan', "value": 81},
2632 1
        }
2633 1
        with pytest.raises(ValueError):
2634 1
            self.napp._uni_from_dict(uni_dict)
2635 1
2636 1
        # case3: success creation
2637
        uni_mock = get_uni_mocked(switch_id="00:01")
2638
        _get_interface_by_id_mock.return_value = uni_mock.interface
2639
        uni = self.napp._uni_from_dict(uni_dict)
2640
        assert uni == uni_mock
2641 1
2642
        # case4: success creation of tag list
2643
        uni_dict["tag"]["value"] = [[1, 10]]
2644
        uni = self.napp._uni_from_dict(uni_dict)
2645 1
        assert isinstance(uni.user_tag, TAGRange)
2646 1
2647 1
        # case5: success creation without tag
2648 1
        uni_mock.user_tag = None
2649 1
        del uni_dict["tag"]
2650 1
        uni = self.napp._uni_from_dict(uni_dict)
2651 1
        assert uni == uni_mock
2652 1
2653 1
    def test_handle_flow_delete(self):
2654
        """Test handle_flow_delete method"""
2655 1
        flow = MagicMock()
2656
        flow.cookie = 0xaa00000000000011
2657 1
        event = MagicMock()
2658 1
        event.content = {'flow': flow}
2659 1
        evc = create_autospec(EVC)
2660 1
        evc.set_flow_removed_at = MagicMock()
2661 1
        self.napp.circuits = {"00000000000011": evc}
2662
        self.napp.handle_flow_delete(event)
2663
        evc.set_flow_removed_at.assert_called_once()
2664
2665 View Code Duplication
    async def test_add_bulk_metadata(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2666 1
        """Test add_bulk_metadata method"""
2667
        self.napp.controller.loop = asyncio.get_running_loop()
2668
        evc_mock = create_autospec(EVC)
2669
        evc_mock.id = 1234
2670
        self.napp.circuits = {"1234": evc_mock}
2671
        payload = {
2672
            "circuit_ids": ["1234"],
2673 1
            "metadata1": 1,
2674
            "metadata2": 2
2675 1
        }
2676 1
        response = await self.api_client.post(
2677 1
            f"{self.base_endpoint}/v2/evc/metadata",
2678 1
            json=payload
2679 1
        )
2680
        assert response.status_code == 201
2681
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2682 1
        ids = payload.pop("circuit_ids")
2683
        assert args[0] == ids
2684
        assert args[1] == payload
2685
        assert args[2] == "add"
2686
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2687
        assert calls == 1
2688 1
        evc_mock.extend_metadata.assert_called_with(payload)
2689
2690 1
    async def test_add_bulk_metadata_empty_list(self):
2691 1
        """Test add_bulk_metadata method empty list"""
2692 1
        self.napp.controller.loop = asyncio.get_running_loop()
2693 1
        evc_mock = create_autospec(EVC)
2694 1
        evc_mock.id = 1234
2695
        self.napp.circuits = {"1234": evc_mock}
2696
        payload = {
2697 1
            "circuit_ids": [],
2698
            "metadata1": 1,
2699
            "metadata2": 2
2700
        }
2701
        response = await self.api_client.post(
2702
            f"{self.base_endpoint}/v2/evc/metadata",
2703 1
            json=payload
2704
        )
2705 1
        assert response.status_code == 400
2706 1
        assert "invalid" in response.json()["description"]
2707 1
2708 1
    async def test_add_bulk_metadata_no_id(self):
2709 1
        """Test add_bulk_metadata with unknown evc id"""
2710
        self.napp.controller.loop = asyncio.get_running_loop()
2711
        evc_mock = create_autospec(EVC)
2712 1
        evc_mock.id = 1234
2713
        self.napp.circuits = {"1234": evc_mock}
2714
        payload = {
2715
            "circuit_ids": ["1234", "4567"]
2716
        }
2717 1
        response = await self.api_client.post(
2718 1
            f"{self.base_endpoint}/v2/evc/metadata",
2719 1
            json=payload
2720 1
        )
2721 1
        assert response.status_code == 404
2722 1
2723 1
    async def test_add_bulk_metadata_no_circuits(self):
2724 1
        """Test add_bulk_metadata without circuit_ids"""
2725
        self.napp.controller.loop = asyncio.get_running_loop()
2726 1
        evc_mock = create_autospec(EVC)
2727
        evc_mock.id = 1234
2728 1
        self.napp.circuits = {"1234": evc_mock}
2729 1
        payload = {
2730 1
            "metadata": "data"
2731 1
        }
2732 1
        response = await self.api_client.post(
2733 1
            f"{self.base_endpoint}/v2/evc/metadata",
2734
            json=payload
2735
        )
2736
        assert response.status_code == 400
2737
2738 View Code Duplication
    async def test_delete_bulk_metadata(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2739
        """Test delete_metadata method"""
2740
        self.napp.controller.loop = asyncio.get_running_loop()
2741 1
        evc_mock = create_autospec(EVC)
2742
        evc_mock.id = 1234
2743 1
        self.napp.circuits = {"1234": evc_mock}
2744 1
        payload = {
2745 1
            "circuit_ids": ["1234"]
2746 1
        }
2747 1
        response = await self.api_client.request(
2748 1
            "DELETE",
2749 1
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2750
            json=payload
2751
        )
2752 1
        assert response.status_code == 200
2753 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2754 1
        assert args[0] == payload["circuit_ids"]
2755 1
        assert args[1] == {"metadata1": ""}
2756 1
        assert args[2] == "del"
2757
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2758 1
        assert calls == 1
2759 1
        assert evc_mock.remove_metadata.call_count == 1
2760 1
2761 1
    async def test_delete_bulk_metadata_error(self):
2762 1
        """Test bulk_delete_metadata with ciruit erroring"""
2763
        self.napp.controller.loop = asyncio.get_running_loop()
2764 1
        evc_mock = create_autospec(EVC)
2765
        evcs = [evc_mock, evc_mock]
2766 1
        self.napp.circuits = dict(zip(["1", "2"], evcs))
2767 1
        payload = {"circuit_ids": ["1", "2", "3"]}
2768 1
        response = await self.api_client.request(
2769 1
            "DELETE",
2770 1
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2771 1
            json=payload
2772 1
        )
2773 1
        assert response.status_code == 404, response.data
2774 1
        assert response.json()["description"] == ["3"]
2775 1
2776
    async def test_use_uni_tags(self):
2777 1
        """Test _use_uni_tags"""
2778 1
        self.napp.controller.loop = asyncio.get_running_loop()
2779 1
        evc_mock = create_autospec(EVC)
2780 1
        evc_mock.uni_a = "uni_a_mock"
2781
        evc_mock.uni_z = "uni_z_mock"
2782 1
        self.napp._use_uni_tags(evc_mock)
2783 1
        assert evc_mock._use_uni_vlan.call_count == 2
2784
        assert evc_mock._use_uni_vlan.call_args[0][0] == evc_mock.uni_z
2785 1
2786 1
        # One UNI tag is not available
2787
        evc_mock._use_uni_vlan.side_effect = [KytosTagError(""), None]
2788 1
        with pytest.raises(KytosTagError):
2789 1
            self.napp._use_uni_tags(evc_mock)
2790 1
        assert evc_mock._use_uni_vlan.call_count == 3
2791 1
        assert evc_mock.make_uni_vlan_available.call_count == 0
2792
2793
        evc_mock._use_uni_vlan.side_effect = [None, KytosTagError("")]
2794
        with pytest.raises(KytosTagError):
2795
            self.napp._use_uni_tags(evc_mock)
2796
        assert evc_mock._use_uni_vlan.call_count == 5
2797
        assert evc_mock.make_uni_vlan_available.call_count == 1
2798 1
2799 1
    def test_check_no_tag_duplication(self):
2800 1
        """Test _check_no_tag_duplication"""
2801
        evc = MagicMock()
2802
        evc.check_no_tag_duplicate = MagicMock()
2803 1
        evc.archived = False
2804 1
        evc.id = "1"
2805 1
        self.napp.circuits = {"1": evc}
2806 1
        evc_id = "2"
2807 1
        uni_a = get_uni_mocked(valid=True)
2808 1
        uni_z = get_uni_mocked(valid=True)
2809
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2810
        assert evc.check_no_tag_duplicate.call_count == 0
2811 1
2812 1
        uni_a.user_tag = None
2813 1
        uni_z.user_tag = None
2814 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2815 1
        assert evc.check_no_tag_duplicate.call_count == 2
2816
2817
        self.napp._check_no_tag_duplication(evc_id, uni_a, None)
2818 1
        assert evc.check_no_tag_duplicate.call_count == 3
2819 1
2820 1
        self.napp._check_no_tag_duplication(evc_id, None, None)
2821 1
        assert evc.check_no_tag_duplicate.call_count == 3
2822 1
2823
    @patch("napps.kytos.mef_eline.main.time")
2824 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_up")
2825 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_down")
2826 1
    def test_handle_on_interface_link_change(
2827 1
        self,
2828
        mock_down,
2829
        mock_up,
2830 1
        mock_time
2831 1
    ):
2832
        """Test handle_on_interface_link_change"""
2833 1
        mock_time.sleep.return_value = True
2834 1
        mock_intf = Mock()
2835 1
        mock_intf.id = "mock_intf"
2836
2837
        # Created/link_up
2838
        name = '.*.switch.interface.created'
2839
        content = {"interface": mock_intf}
2840
        event = KytosEvent(name=name, content=content)
2841
        self.napp.handle_on_interface_link_change(event)
2842
        assert mock_down.call_count == 0
2843
        assert mock_up.call_count == 1
2844
2845
        # Deleted/link_down
2846
        name = '.*.switch.interface.deleted'
2847
        event = KytosEvent(name=name, content=content)
2848
        self.napp.handle_on_interface_link_change(event)
2849
        assert mock_down.call_count == 1
2850
        assert mock_up.call_count == 1
2851
2852
        # Event delay
2853
        self.napp._intf_events[mock_intf.id]["last_acquired"] = "mock_time"
2854
        for _ in range(1, 6):
2855
            self.napp.handle_on_interface_link_change(event)
2856
        assert mock_down.call_count == 1
2857
        assert mock_up.call_count == 1
2858
2859
        self.napp._intf_events[mock_intf.id].pop("last_acquired")
2860
        self.napp.handle_on_interface_link_change(event)
2861
        assert mock_down.call_count == 2
2862
        assert mock_up.call_count == 1
2863
2864
        # Out of order event
2865
        event = KytosEvent(name=name, content=content)
2866
        self.napp._intf_events[mock_intf.id]["event"] = Mock(timestamp=now())
2867
2868
        self.napp.handle_on_interface_link_change(event)
2869
        assert mock_down.call_count == 2
2870
        assert mock_up.call_count == 1
2871
2872
    def test_handle_evc_deployed(
2873
        self,
2874
    ):
2875
        evc1 = MagicMock()
2876
        evc1.is_eligible_for_failover_path.return_value = True
2877
        evc1.is_active.return_value = True
2878
        evc1.failover_path = Path([])
2879
        evc1.current_path = ["LINK"]
2880
2881
        evc2 = MagicMock()
2882
        evc2.is_eligible_for_failover_path.return_value = False
2883
        evc2.is_active.return_value = True
2884
        evc2.failover_path = Path([])
2885
        evc2.current_path = ["LINK"]
2886
2887
        self.napp.circuits = {
2888
            "evc_1": evc1,
2889
            "evc_2": evc2,
2890
        }
2891
2892
        event = KytosEvent(
2893
            name="kytos/mef_eline.need_failover",
2894
            content={
2895
                "evc_id": "evc_1",
2896
            }
2897
        )
2898
2899
        self.napp.handle_evc_deployed(event)
2900
        evc1.setup_failover_path.assert_called()
2901
2902
        event = KytosEvent(
2903
            name="kytos/mef_eline.need_failover",
2904
            content={
2905
                "evc_id": "evc_2",
2906
            }
2907
        )
2908
2909
        self.napp.handle_evc_deployed(event)
2910
        evc2.setup_failover_path.assert_not_called()
2911