Test Failed
Pull Request — master (#690)
by
unknown
05:22
created

TestMain.test_create_circuit_already_enabled()   B

Complexity

Conditions 1

Size

Total Lines 69
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 1.0046

Importance

Changes 0
Metric Value
cc 1
eloc 57
nop 10
dl 0
loc 69
ccs 25
cts 30
cp 0.8333
crap 1.0046
rs 8.4072
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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