Test Failed
Pull Request — master (#480)
by Aldo
04:19
created

TestMain.test_update_circuit_invalid_path()   B

Complexity

Conditions 1

Size

Total Lines 84
Code Lines 69

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 38
CRAP Score 1.0003

Importance

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