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

TestMain.test_handle_evc_deployed()   A

Complexity

Conditions 1

Size

Total Lines 39
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 27
nop 1
dl 0
loc 39
ccs 0
cts 0
cp 0
crap 2
rs 9.232
c 0
b 0
f 0
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