Passed
Pull Request — master (#553)
by Aldo
03:58
created

TestMain.test_update_circuit_invalid_json()   B

Complexity

Conditions 1

Size

Total Lines 72
Code Lines 60

Duplication

Lines 72
Ratio 100 %

Code Coverage

Tests 34
CRAP Score 1.0005

Importance

Changes 0
Metric Value
cc 1
eloc 60
nop 10
dl 72
loc 72
ccs 34
cts 37
cp 0.9189
crap 1.0005
rs 8.309
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
        """Test execute_consistency."""
113 1
        (mongo_controller_upsert_mock, mock_settings) = args
114
115 1
        stored_circuits = {'1': {'name': 'circuit_1'},
116
                           '2': {'name': 'circuit_2'},
117
                           '3': {'name': 'circuit_3'}}
118 1
        mongo_controller_upsert_mock.return_value = True
119 1
        self.napp.mongo_controller.get_circuits.return_value = {
120
            "circuits": stored_circuits
121
        }
122
123 1
        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
141 1
        mock_check_list_traces.return_value = {
142
                                                1: True,
143
                                                2: False
144
                                            }
145
146 1
        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
151 1
    @patch('napps.kytos.mef_eline.main.settings')
152 1
    @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
        """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 1
        mongo_controller_upsert_mock.return_value = True
161 1
        self.napp.mongo_controller.get_circuits.return_value = {
162
            "circuits": stored_circuits
163
        }
164
165 1
        mock_settings.WAIT_FOR_OLD_PATH = -1
166 1
        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
178 1
        mock_check_list_traces.return_value = {1: False}
179
180 1
        self.napp.execute_consistency()
181 1
        assert evc1.deploy.call_count == 0
182 1
        self.napp.execute_consistency()
183 1
        assert evc1.deploy.call_count == 1
184
185 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
186 1
    @patch('napps.kytos.mef_eline.models.evc.EVCBase._validate')
187 1
    def test_evc_from_dict(self, _validate_mock, uni_from_dict_mock):
188
        """
189
        Test the helper method that create an EVN from dict.
190
191
        Verify object creation with circuit data and schedule data.
192
        """
193 1
        _validate_mock.return_value = True
194 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
195 1
        payload = {
196
            "name": "my evc1",
197
            "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 1
        evc_response = self.napp._evc_from_dict(payload)
212 1
        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
219 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
220 1
    @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
        self, _get_interface_by_id_mock, _validate_mock, uni_from_dict_mock
224
    ):
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 1
        _get_interface_by_id_mock.return_value = get_uni_mocked().interface
232 1
        _validate_mock.return_value = True
233 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
234 1
        payload = {
235
            "name": "my evc1",
236
            "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 1
        evc_response = self.napp._evc_from_dict(payload)
260 1
        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
269 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
270 1
    @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
        self, _get_interface_by_id_mock, _validate_mock, uni_from_dict_mock
274
    ):
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 1
        _get_interface_by_id_mock.return_value = get_uni_mocked().interface
281 1
        _validate_mock.return_value = True
282 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
283 1
        payload = {
284
            "name": "my evc1",
285
            "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 1
        evc_response = self.napp._evc_from_dict(payload)
314 1
        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
323 1
    async def test_list_without_circuits(self):
324
        """Test if list circuits return 'no circuit stored.'."""
325 1
        circuits = {"circuits": {}}
326 1
        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
332 1
    async def test_list_no_circuits_stored(self):
333
        """Test if list circuits return all circuits stored."""
334 1
        circuits = {"circuits": {}}
335 1
        self.napp.mongo_controller.get_circuits.return_value = circuits
336
337 1
        url = f"{self.base_endpoint}/v2/evc/"
338 1
        response = await self.api_client.get(url)
339 1
        expected_result = circuits["circuits"]
340 1
        assert response.json() == expected_result
341
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": {"name": "circuit_1"}, "2": {"name": "circuit_2"}}
347
        }
348 1
        get_circuits = self.napp.mongo_controller.get_circuits
349 1
        get_circuits.return_value = circuits
350
351 1
        url = f"{self.base_endpoint}/v2/evc/"
352 1
        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
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
            {
362
                "1": {"name": "circuit_1", "archived": True},
363
            }
364
        }
365 1
        get_circuits = self.napp.mongo_controller.get_circuits
366 1
        get_circuits.return_value = circuits
367
368 1
        url = f"{self.base_endpoint}/v2/evc/?archived=true&metadata.a=1"
369 1
        response = await self.api_client.get(url)
370 1
        get_circuits.assert_called_with(archived="true",
371
                                        metadata={"metadata.a": "1"})
372 1
        expected_result = {"1": circuits["circuits"]["1"]}
373 1
        assert response.json() == expected_result
374
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": {"name": "circuit_1"},
380
                "2": {"name": "circuit_2", "archived": True},
381
            }
382
        }
383 1
        self.napp.mongo_controller.get_circuits.return_value = circuits
384
385 1
        url = f"{self.base_endpoint}/v2/evc/?archived=null"
386 1
        response = await self.api_client.get(url)
387 1
        expected_result = circuits["circuits"]
388 1
        assert response.json() == expected_result
389
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 1
        self.napp.mongo_controller.get_circuit.return_value = circuit
394
395 1
        url = f"{self.base_endpoint}/v2/evc/1"
396 1
        response = await self.api_client.get(url)
397 1
        expected_result = circuit
398 1
        assert response.json() == expected_result
399
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 1
        url = f"{self.base_endpoint}/v2/evc/3"
404 1
        response = await self.api_client.get(url)
405
        expected_result = "circuit_id 3 not found"
406
        assert response.json()["description"] == expected_result
407
408 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
409 1
    @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
        self,
419
        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 1
        self.napp.controller.loop = asyncio.get_running_loop()
432 1
        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
449 1
        url = f"{self.base_endpoint}/v2/evc/"
450 1
        payload = {
451
            "name": "my evc1",
452
            "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 1
        response = await self.api_client.post(url, json=payload)
477 1
        current_data = response.json()
478
479
        # verify expected result from request
480 1
        assert 201 == response.status_code
481 1
        assert "circuit_id" in current_data
482
483
        # verify uni called
484 1
        uni_from_dict_mock.called_twice()
485 1
        uni_from_dict_mock.assert_any_call(payload["uni_z"])
486 1
        uni_from_dict_mock.assert_any_call(payload["uni_a"])
487
488
        # verify validation called
489 1
        validate_mock.assert_called_once()
490 1
        validate_mock.assert_called_with(
491
            table_group={'evpl': 0, 'epl': 0},
492
            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 1
        mongo_controller_upsert_mock.assert_called_once()
502
503
        # verify evc as dict is called to save in the box
504 1
        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 1
        url = f"{self.base_endpoint}/v2/evc/"
512
513 1
        response = await self.api_client.post(url)
514
        current_data = response.json()
515
        assert 400 == response.status_code
516
        assert "Missing required request body" in current_data["description"]
517
518 1
    async def test_create_a_circuit_case_3(self):
519
        """Test create a new circuit trying to send request with an
520
        invalid json."""
521 1
        self.napp.controller.loop = asyncio.get_running_loop()
522 1
        url = f"{self.base_endpoint}/v2/evc/"
523
524 1
        response = await self.api_client.post(
525
            url,
526
            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 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
533 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
534 1
    async def test_create_a_circuit_case_4(
535
        self,
536
        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 1
        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 1
        mongo_controller_upsert_mock.return_value = True
545 1
        url = f"{self.base_endpoint}/v2/evc/"
546
547 1
        payload = {
548
            "name": "my evc1",
549
            "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 1
        response = await self.api_client.post(url, json=payload)
561
        current_data = response.json()
562
        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 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
571 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
572 1
    async def test_create_a_circuit_case_5(
573
        self,
574
        validate_mock,
575
        uni_from_dict_mock
576
    ):
577
        """Test create a new intra circuit with a disabled switch"""
578 1
        self.napp.controller.loop = asyncio.get_running_loop()
579 1
        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
            "name": "my evc1",
589
            "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 1
        response = await self.api_client.post(url, json=payload)
601
        assert 409 == response.status_code, response.data
602
603 1
    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 1
        url = f"{self.base_endpoint}/v2/evc/"
607
608 1
        payload = {
609
            "name": "my evc1",
610
            "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 1
        response = await self.api_client.post(url, json=payload)
621
        current_data = response.json()
622
        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 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
628 1
    @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
        self,
638
        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 1
        self.napp.controller.loop = asyncio.get_running_loop()
651 1
        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
            None, KytosTagError("The EVC already exists.")
659
        ]
660 1
        uni1 = create_autospec(UNI)
661 1
        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
668 1
        payload = {
669
            "name": "my evc1",
670
            "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 1
        evc_as_dict_mock.return_value = payload
682 1
        response = await self.api_client.post(
683
            f"{self.base_endpoint}/v2/evc/",
684
            json=payload
685
        )
686 1
        assert 201 == response.status_code
687
688 1
        response = await self.api_client.post(
689
            f"{self.base_endpoint}/v2/evc/",
690
            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 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
698 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
699 1
    async def test_create_circuit_case_5(
700
        self,
701
        uni_from_dict_mock,
702
        mock_tags_equal
703
    ):
704
        """Test when neither primary path nor dynamic_backup_path is set."""
705 1
        self.napp.controller.loop = asyncio.get_running_loop()
706 1
        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
716 1
        payload = {
717
            "name": "my evc1",
718
            "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 1
        response = await self.api_client.post(url, json=payload)
730
        current_data = response.json()
731
        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 1
    @patch("napps.kytos.mef_eline.main.Main._evc_from_dict")
737 1
    async def test_create_circuit_case_6(self, mock_evc):
738
        """Test create_circuit with KytosTagError"""
739 1
        self.napp.controller.loop = asyncio.get_running_loop()
740 1
        url = f"{self.base_endpoint}/v2/evc/"
741 1
        mock_evc.side_effect = KytosTagError("")
742 1
        payload = {
743
            "name": "my evc1",
744
            "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 1
        response = await self.api_client.post(url, json=payload)
752
        assert response.status_code == 400, response.data
753
754 1
    @patch("napps.kytos.mef_eline.main.check_disabled_component")
755 1
    @patch("napps.kytos.mef_eline.main.Main._evc_from_dict")
756 1
    async def test_create_circuit_case_7(
757
        self,
758
        mock_evc,
759
        mock_check_disabled_component
760
    ):
761
        """Test create_circuit with InvalidPath"""
762 1
        self.napp.controller.loop = asyncio.get_running_loop()
763 1
        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
771
        # Backup_path invalid
772 1
        evc.backup_path.is_valid = MagicMock(side_effect=InvalidPath)
773 1
        mock_evc.return_value = evc
774 1
        payload = {
775
            "name": "my evc1",
776
            "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 1
        response = await self.api_client.post(url, json=payload)
784
        assert response.status_code == 400, response.data
785
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 1
    @patch("napps.kytos.mef_eline.main.check_disabled_component")
794 1
    @patch("napps.kytos.mef_eline.main.Main._evc_from_dict")
795 1
    async def test_create_circuit_case_8(
796
        self,
797
        mock_evc,
798
        mock_check_disabled_component
799
    ):
800
        """Test create_circuit wit no equal tag lists"""
801 1
        self.napp.controller.loop = asyncio.get_running_loop()
802 1
        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
            "name": "my evc1",
811
            "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 1
        response = await self.api_client.post(url, json=payload)
821
        assert response.status_code == 400, response.data
822
823 1
    async def test_redeploy_evc(self):
824
        """Test endpoint to redeploy an EVC."""
825 1
        evc1 = MagicMock()
826 1
        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
834 1
    async def test_redeploy_evc_disabled(self):
835
        """Test endpoint to redeploy an EVC."""
836 1
        evc1 = MagicMock()
837 1
        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
845 1
    async def test_redeploy_evc_deleted(self):
846
        """Test endpoint to redeploy an EVC."""
847 1
        evc1 = MagicMock()
848 1
        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
        assert response.status_code == 404, response.data
853
854 1
    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 1
        assert response.status_code == 200
862 1
        assert not response.json()
863
864 1
    def _add_mongodb_schedule_data(self, data_mock):
865
        """Add schedule data to mongodb mock object."""
866 1
        circuits = {"circuits": {}}
867 1
        payload_1 = {
868
            "id": "aa:aa:aa",
869
            "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 1
        circuits["circuits"].update({"aa:aa:aa": payload_1})
884 1
        payload_2 = {
885
            "id": "bb:bb:bb",
886
            "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 1
        circuits["circuits"].update({"bb:bb:bb": payload_2})
901 1
        payload_3 = {
902
            "id": "cc:cc:cc",
903
            "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 1
        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
        )
922
923 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
924
925
        # Call URL
926 1
        response = await self.api_client.get(url)
927
        # Expected JSON data from response
928 1
        expected = [
929
            {
930
                "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 1
        assert response.status_code == 200
968 1
        assert expected == response.json()
969
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
        )
975
976 1
        requested_circuit_id = "bb:bb:bb"
977 1
        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
982
        # Call URL
983 1
        response = await self.api_client.get(url)
984
985
        # Expected JSON data from response
986 1
        expected = [
987
            {"action": "create", "frequency": "1 * * * *", "id": "3"},
988
            {"action": "remove", "frequency": "2 * * * *", "id": "4"},
989
        ]
990
991 1
        assert response.status_code == 200
992 1
        assert expected == response.json()["circuit_scheduler"]
993
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 1
        self.napp.mongo_controller.get_circuit.return_value = None
998 1
        url = f"{self.base_endpoint}/v2/evc/{requested_id}"
999
1000
        # Call URL
1001 1
        response = await self.api_client.get(url)
1002
1003
        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 1
    def _uni_from_dict_side_effect(self, uni_dict):
1009 1
        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
1014 1
    @patch("apscheduler.schedulers.background.BackgroundScheduler.add_job")
1015 1
    @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
        self,
1022
        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 1
        self.napp.controller.loop = asyncio.get_running_loop()
1031 1
        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
1037 1
        self._add_mongodb_schedule_data(
1038
            self.napp.mongo_controller.get_circuits
1039
        )
1040
1041 1
        requested_id = "bb:bb:bb"
1042 1
        url = f"{self.base_endpoint}/v2/evc/schedule/"
1043
1044 1
        payload = {
1045
            "circuit_id": requested_id,
1046
            "schedule": {"frequency": "1 * * * *", "action": "create"},
1047
            "metadata": {"metadata1": "test_data"},
1048
        }
1049
1050
        # Call URL
1051 1
        response = await self.api_client.post(url, json=payload)
1052 1
        response_json = response.json()
1053
1054 1
        assert response.status_code == 201
1055 1
        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
1061
        # Case 2: there is no schedule
1062 1
        payload = {
1063
              "circuit_id": "cc:cc:cc",
1064
              "schedule": {
1065
                "frequency": "1 * * * *",
1066
                "action": "create"
1067
              }
1068
            }
1069 1
        response = await self.api_client.post(url, json=payload)
1070 1
        assert response.status_code == 201
1071
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 1
        evc1 = MagicMock()
1076 1
        self.napp.circuits = {'bb:bb:bb': evc1}
1077 1
        url = f'{self.base_endpoint}/v2/evc/schedule/'
1078
1079
        # case 1: empty post
1080 1
        response = await self.api_client.post(url, json={})
1081
        assert response.status_code == 400
1082
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 1
    @patch('apscheduler.schedulers.background.BackgroundScheduler.remove_job')
1121 1
    @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
        self,
1128
        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 1
        self.napp.controller.loop = asyncio.get_running_loop()
1137 1
        mongo_payload_1 = {
1138
            "circuits": {
1139
                "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 1
        validate_mock.return_value = True
1162 1
        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
1169 1
        requested_schedule_id = "1"
1170 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1171
1172 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1173
1174
        # Call URL
1175 1
        response = await self.api_client.patch(url, json=payload)
1176 1
        response_json = response.json()
1177
1178 1
        assert response.status_code == 200
1179 1
        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
1185 1
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1186 1
    async def test_update_no_schedule(
1187
        self, find_evc_by_schedule_id_mock
1188
    ):
1189
        """Test update a circuit schedule."""
1190 1
        self.napp.controller.loop = asyncio.get_running_loop()
1191 1
        url = f"{self.base_endpoint}/v2/evc/schedule/1"
1192 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1193
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
1199 1
    @patch("apscheduler.schedulers.background.BackgroundScheduler.remove_job")
1200 1
    @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
        """Test create a circuit schedule."""
1206 1
        (
1207
            validate_mock,
1208
            evc_as_dict_mock,
1209
            mongo_controller_upsert_mock,
1210
            uni_from_dict_mock,
1211
            scheduler_remove_job_mock,
1212
        ) = args
1213
1214 1
        mongo_payload_1 = {
1215
            "circuits": {
1216
                "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 1
        validate_mock.return_value = True
1238 1
        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
1244 1
        requested_schedule_id = "1"
1245 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1246
1247
        # Call URL
1248 1
        response = await self.api_client.delete(url)
1249
1250 1
        assert response.status_code == 200
1251 1
        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
1255 1
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1256 1
    async def test_delete_schedule_not_found(self, mock_find_evc_by_sched):
1257
        """Test delete a circuit schedule - unexisting."""
1258 1
        mock_find_evc_by_sched.return_value = (None, False)
1259 1
        url = f'{self.base_endpoint}/v2/evc/schedule/1'
1260 1
        response = await self.api_client.delete(url)
1261
        assert response.status_code == 404
1262
1263 1
    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 1
        evcs = {i: MagicMock(service_level=v, creation_time=1)
1267
                for i, v in enumerate(levels)}
1268 1
        self.napp.circuits = evcs
1269 1
        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
1273 1
        for evc, exp_level in zip(evcs_by_level, expected_levels):
1274 1
            assert evc.service_level == exp_level
1275
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 1
        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
1283 1
        self.napp.circuits[1].is_enabled = lambda: False
1284 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1285 1
        assert len(evcs_by_level) == 1
1286
1287 1
        self.napp.circuits[1].is_enabled = lambda: False
1288 1
        evcs_by_level = self.napp.get_evcs_by_svc_level(enable_filter=False)
1289 1
        assert len(evcs_by_level) == 2
1290
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 1
        url = f'{self.base_endpoint}/v2/evc/1234'
1295 1
        response = await self.api_client.get(url)
1296
        assert response.status_code == 404
1297
1298 1
    @patch('httpx.post')
1299 1
    @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
        self,
1311
        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
        httpx_mock
1322
    ):
1323
        """Test update a circuit circuit."""
1324 1
        self.napp.controller.loop = asyncio.get_running_loop()
1325 1
        mock_use_uni_tags.return_value = True
1326 1
        evc_deploy.return_value = True
1327 1
        interface_by_id_mock.return_value = get_uni_mocked().interface
1328 1
        unis = [
1329
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:01"),
1330
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:02"),
1331
        ]
1332 1
        uni_from_dict_mock.side_effect = 2 * unis
1333
1334 1
        response = MagicMock()
1335 1
        response.status_code = 201
1336 1
        httpx_mock.return_value = response
1337
1338 1
        payloads = [
1339
            {
1340
                "name": "my evc1",
1341
                "uni_a": {
1342
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1343
                    "tag": {"tag_type": 'vlan', "value": 80},
1344
                },
1345
                "uni_z": {
1346
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1347
                    "tag": {"tag_type": 'vlan', "value": 1},
1348
                },
1349
                "dynamic_backup_path": True,
1350
            },
1351
            {
1352
                "primary_path": [
1353
                    {
1354
                        "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1355
                        "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1356
                    }
1357
                ]
1358
            },
1359
            {
1360
                "sb_priority": 3
1361
            },
1362
            {
1363
                # It works only with 'enabled' and not with 'enable'
1364
                "enabled": True
1365
            },
1366
            {
1367
                "sb_priority": 100
1368
            }
1369
        ]
1370
1371 1
        evc_as_dict_mock.return_value = payloads[0]
1372 1
        response = await self.api_client.post(
1373
            f"{self.base_endpoint}/v2/evc/",
1374
            json=payloads[0],
1375
        )
1376 1
        assert 201 == response.status_code
1377
1378 1
        evc_deploy.reset_mock()
1379 1
        evc_as_dict_mock.return_value = payloads[1]
1380 1
        current_data = response.json()
1381 1
        circuit_id = current_data["circuit_id"]
1382 1
        response = await self.api_client.patch(
1383
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1384
            json=payloads[1],
1385
        )
1386
        # evc_deploy.assert_called_once()
1387 1
        assert 200 == response.status_code
1388
1389 1
        evc_deploy.reset_mock()
1390 1
        evc_as_dict_mock.return_value = payloads[2]
1391 1
        response = await self.api_client.patch(
1392
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1393
            json=payloads[2],
1394
        )
1395 1
        evc_deploy.assert_not_called()
1396 1
        assert 200 == response.status_code
1397
1398 1
        evc_deploy.reset_mock()
1399 1
        evc_as_dict_mock.return_value = payloads[3]
1400 1
        response = await self.api_client.patch(
1401
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1402
            json=payloads[3],
1403
        )
1404 1
        evc_deploy.assert_called_once()
1405 1
        assert 200 == response.status_code
1406
1407 1
        evc_deploy.reset_mock()
1408 1
        response = await self.api_client.patch(
1409
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1410
            content=b'{"priority":5,}',
1411
            headers={"Content-Type": "application/json"}
1412
        )
1413
        evc_deploy.assert_not_called()
1414
        assert 400 == response.status_code
1415
1416
        response = await self.api_client.patch(
1417
            f"{self.base_endpoint}/v2/evc/1234",
1418
            json=payloads[1],
1419
        )
1420
        current_data = response.json()
1421
        expected_data = "circuit_id 1234 not found"
1422
        assert current_data["description"] == expected_data
1423
        assert 404 == response.status_code
1424
1425
        self.napp.circuits[circuit_id]._active = False
1426
        evc_deploy.reset_mock()
1427
        response = await self.api_client.patch(
1428
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1429
            json=payloads[4]
1430
        )
1431 1
        assert 200 == response.status_code
1432 1
        evc_deploy.assert_called_once()
1433
1434 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...
1435 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1436 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1437 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1438 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1439 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1440 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1441 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1442 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1443 1
    async def test_update_circuit_invalid_json(
1444
        self,
1445
        evc_as_dict_mock,
1446
        validate_mock,
1447
        mongo_controller_upsert_mock,
1448
        uni_from_dict_mock,
1449
        sched_add_mock,
1450
        evc_deploy_mock,
1451
        mock_use_uni_tags,
1452
        mock_tags_equal,
1453
        mock_check_duplicate
1454
    ):
1455
        """Test update a circuit circuit."""
1456 1
        self.napp.controller.loop = asyncio.get_running_loop()
1457 1
        validate_mock.return_value = True
1458 1
        mongo_controller_upsert_mock.return_value = True
1459 1
        sched_add_mock.return_value = True
1460 1
        evc_deploy_mock.return_value = True
1461 1
        mock_use_uni_tags.return_value = True
1462 1
        mock_tags_equal.return_value = True
1463 1
        mock_check_duplicate.return_value = True
1464 1
        uni1 = create_autospec(UNI)
1465 1
        uni2 = create_autospec(UNI)
1466 1
        uni1.interface = create_autospec(Interface)
1467 1
        uni2.interface = create_autospec(Interface)
1468 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1469 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1470 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1471
1472 1
        payload1 = {
1473
            "name": "my evc1",
1474
            "uni_a": {
1475
                "interface_id": "00:00:00:00:00:00:00:01:1",
1476
                "tag": {"tag_type": 'vlan', "value": 80},
1477
            },
1478
            "uni_z": {
1479
                "interface_id": "00:00:00:00:00:00:00:02:2",
1480
                "tag": {"tag_type": 'vlan', "value": 1},
1481
            },
1482
            "dynamic_backup_path": True,
1483
        }
1484
1485 1
        payload2 = {
1486
            "dynamic_backup_path": False,
1487
        }
1488
1489 1
        evc_as_dict_mock.return_value = payload1
1490 1
        response = await self.api_client.post(
1491
            f"{self.base_endpoint}/v2/evc/",
1492
            json=payload1
1493
        )
1494 1
        assert 201 == response.status_code
1495
1496 1
        evc_as_dict_mock.return_value = payload2
1497 1
        current_data = response.json()
1498 1
        circuit_id = current_data["circuit_id"]
1499 1
        response = await self.api_client.patch(
1500
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1501
            json=payload2
1502
        )
1503
        current_data = response.json()
1504
        assert 400 == response.status_code
1505
        assert "must have a primary path or" in current_data["description"]
1506
1507 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
1508 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1509 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1510 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1511 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1512 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1513 1
    @patch("napps.kytos.mef_eline.main.Main._link_from_dict")
1514 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1515 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1516 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1517 1
    @patch("napps.kytos.mef_eline.models.path.Path.is_valid")
1518 1
    async def test_update_circuit_invalid_path(
1519
        self,
1520
        is_valid_mock,
1521
        evc_as_dict_mock,
1522
        validate_mock,
1523
        mongo_controller_upsert_mock,
1524
        link_from_dict_mock,
1525
        uni_from_dict_mock,
1526
        sched_add_mock,
1527
        evc_deploy_mock,
1528
        mock_use_uni_tags,
1529
        mock_tags_equal,
1530
        mock_check_duplicate
1531
    ):
1532
        """Test update a circuit circuit."""
1533 1
        self.napp.controller.loop = asyncio.get_running_loop()
1534 1
        is_valid_mock.side_effect = InvalidPath("error")
1535 1
        validate_mock.return_value = True
1536 1
        mongo_controller_upsert_mock.return_value = True
1537 1
        sched_add_mock.return_value = True
1538 1
        evc_deploy_mock.return_value = True
1539 1
        mock_use_uni_tags.return_value = True
1540 1
        link_from_dict_mock.return_value = 1
1541 1
        mock_tags_equal.return_value = True
1542 1
        mock_check_duplicate.return_value = True
1543 1
        uni1 = create_autospec(UNI)
1544 1
        uni2 = create_autospec(UNI)
1545 1
        uni1.interface = create_autospec(Interface)
1546 1
        uni2.interface = create_autospec(Interface)
1547 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1548 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1549 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1550
1551 1
        payload1 = {
1552
            "name": "my evc1",
1553
            "uni_a": {
1554
                "interface_id": "00:00:00:00:00:00:00:01:1",
1555
                "tag": {"tag_type": 'vlan', "value": 80},
1556
            },
1557
            "uni_z": {
1558
                "interface_id": "00:00:00:00:00:00:00:02:2",
1559
                "tag": {"tag_type": 'vlan', "value": 1},
1560
            },
1561
            "dynamic_backup_path": True,
1562
        }
1563
1564 1
        payload2 = {
1565
            "primary_path": [
1566
                {
1567
                    "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1568
                    "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1569
                }
1570
            ]
1571
        }
1572
1573 1
        evc_as_dict_mock.return_value = payload1
1574 1
        response = await self.api_client.post(
1575
            f"{self.base_endpoint}/v2/evc/",
1576
            json=payload1,
1577
        )
1578 1
        assert 201 == response.status_code
1579
1580 1
        evc_as_dict_mock.return_value = payload2
1581 1
        current_data = response.json()
1582 1
        circuit_id = current_data["circuit_id"]
1583 1
        response = await self.api_client.patch(
1584
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1585
            json=payload2,
1586
        )
1587
        current_data = response.json()
1588
        expected_data = "primary_path is not a valid path: error"
1589
        assert 400 == response.status_code
1590
        assert current_data["description"] == expected_data
1591
1592 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._get_unis_use_tags")
1593 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1594 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1595 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1596 1
    @patch('napps.kytos.mef_eline.models.evc.EVCDeploy.deploy')
1597 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1598 1
    async def test_update_disabled_intra_switch(
1599
        self,
1600
        uni_from_dict_mock,
1601
        evc_deploy,
1602
        _mock_validate,
1603
        _mongo_controller_upsert_mock,
1604
        mock_use_uni_tags,
1605
        mock_get_unis
1606
    ):
1607
        """Test update a circuit that result in an intra-switch EVC
1608
        with disabled switches or interfaces"""
1609 1
        evc_deploy.return_value = True
1610 1
        _mock_validate.return_value = True
1611 1
        _mongo_controller_upsert_mock.return_value = True
1612 1
        mock_use_uni_tags.return_value = True
1613 1
        self.napp.controller.loop = asyncio.get_running_loop()
1614
        # Interfaces from get_uni_mocked() are disabled
1615 1
        uni_a = get_uni_mocked(
1616
            switch_dpid="00:00:00:00:00:00:00:01",
1617
            switch_id="00:00:00:00:00:00:00:01"
1618
        )
1619 1
        uni_z = get_uni_mocked(
1620
            switch_dpid="00:00:00:00:00:00:00:02",
1621
            switch_id="00:00:00:00:00:00:00:02"
1622
        )
1623 1
        unis = [uni_a, uni_z]
1624 1
        uni_from_dict_mock.side_effect = 2 * unis
1625
1626 1
        evc_payload = {
1627
            "name": "Intra-EVC",
1628
            "dynamic_backup_path": True,
1629
            "uni_a": {
1630
                "tag": {"value": 101, "tag_type": 'vlan'},
1631
                "interface_id": "00:00:00:00:00:00:00:02:2"
1632
            },
1633
            "uni_z": {
1634
                "tag": {"value": 101, "tag_type": 'vlan'},
1635
                "interface_id": "00:00:00:00:00:00:00:01:1"
1636
            }
1637
        }
1638
1639
        # With this update the EVC will be intra-switch
1640 1
        update_payload = {
1641
            "uni_z": {
1642
                "tag": {"value": 101, "tag_type": 'vlan'},
1643
                "interface_id": "00:00:00:00:00:00:00:02:1"
1644
            }
1645
        }
1646
        # Same mocks = intra-switch
1647 1
        mock_get_unis.return_value = [uni_z, uni_z]
1648 1
        response = await self.api_client.post(
1649
            f"{self.base_endpoint}/v2/evc/",
1650
            json=evc_payload,
1651
        )
1652 1
        assert 201 == response.status_code
1653 1
        current_data = response.json()
1654 1
        circuit_id = current_data["circuit_id"]
1655
1656 1
        response = await self.api_client.patch(
1657
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1658
            json=update_payload,
1659
        )
1660
        assert 409 == response.status_code
1661
        description = "00:00:00:00:00:00:00:02:1 is disabled"
1662
        assert description in response.json()["description"]
1663
1664 1
    def test_link_from_dict_non_existent_intf(self):
1665
        """Test _link_from_dict non existent intf."""
1666 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1667 1
        link_dict = {
1668
            "endpoint_a": {"id": "a"},
1669
            "endpoint_b": {"id": "b"}
1670
        }
1671 1
        with pytest.raises(ValueError):
1672 1
            self.napp._link_from_dict(link_dict, "current_path")
1673
1674 1
    def test_link_from_dict_vlan_metadata(self):
1675
        """Test that link_from_dict only accepts vlans for current_path
1676
         and failover_path."""
1677 1
        intf = MagicMock(id="01:1")
1678 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=intf)
1679 1
        link_dict = {
1680
            'id': 'mock_link',
1681
            'endpoint_a': {'id': '00:00:00:00:00:00:00:01:4'},
1682
            'endpoint_b': {'id': '00:00:00:00:00:00:00:05:2'},
1683
            'metadata': {'s_vlan': {'tag_type': 'vlan', 'value': 1}}
1684
        }
1685 1
        link = self.napp._link_from_dict(link_dict, "current_path")
1686 1
        assert link.metadata.get('s_vlan', None)
1687
1688 1
        link = self.napp._link_from_dict(link_dict, "failover_path")
1689 1
        assert link.metadata.get('s_vlan', None)
1690
1691 1
        link = self.napp._link_from_dict(link_dict, "primary_path")
1692 1
        assert link.metadata.get('s_vlan', None) is None
1693
1694 1
    def test_uni_from_dict_non_existent_intf(self):
1695
        """Test _link_from_dict non existent intf."""
1696 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1697 1
        uni_dict = {
1698
            "interface_id": "aaa",
1699
        }
1700 1
        with pytest.raises(ValueError):
1701 1
            self.napp._uni_from_dict(uni_dict)
1702
1703 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...
1704 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1705 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1706 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1707 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1708 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1709 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1710 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1711 1
    async def test_update_evc_no_json_mime(
1712
        self,
1713
        mongo_controller_upsert_mock,
1714
        validate_mock,
1715
        uni_from_dict_mock,
1716
        sched_add_mock,
1717
        evc_deploy_mock,
1718
        mock_use_uni_tags,
1719
        mock_tags_equal,
1720
        mock_check_duplicate
1721
    ):
1722
        """Test update a circuit with wrong mimetype."""
1723 1
        self.napp.controller.loop = asyncio.get_running_loop()
1724 1
        validate_mock.return_value = True
1725 1
        sched_add_mock.return_value = True
1726 1
        evc_deploy_mock.return_value = True
1727 1
        mock_use_uni_tags.return_value = True
1728 1
        mock_tags_equal.return_value = True
1729 1
        mock_check_duplicate.return_value = True
1730 1
        uni1 = create_autospec(UNI)
1731 1
        uni2 = create_autospec(UNI)
1732 1
        uni1.interface = create_autospec(Interface)
1733 1
        uni2.interface = create_autospec(Interface)
1734 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1735 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1736 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1737 1
        mongo_controller_upsert_mock.return_value = True
1738
1739 1
        payload1 = {
1740
            "name": "my evc1",
1741
            "uni_a": {
1742
                "interface_id": "00:00:00:00:00:00:00:01:1",
1743
                "tag": {"tag_type": 'vlan', "value": 80},
1744
            },
1745
            "uni_z": {
1746
                "interface_id": "00:00:00:00:00:00:00:02:2",
1747
                "tag": {"tag_type": 'vlan', "value": 1},
1748
            },
1749
            "dynamic_backup_path": True,
1750
        }
1751
1752 1
        payload2 = {"dynamic_backup_path": False}
1753
1754 1
        response = await self.api_client.post(
1755
            f"{self.base_endpoint}/v2/evc/",
1756
            json=payload1,
1757
        )
1758 1
        assert 201 == response.status_code
1759
1760 1
        current_data = response.json()
1761 1
        circuit_id = current_data["circuit_id"]
1762 1
        response = await self.api_client.patch(
1763
            f"{self.base_endpoint}/v2/evc/{circuit_id}", data=payload2
1764
        )
1765
        current_data = response.json()
1766
        assert 415 == response.status_code
1767
        assert "application/json" in current_data["description"]
1768
1769 1
    async def test_delete_no_evc(self):
1770
        """Test delete when EVC does not exist."""
1771 1
        url = f"{self.base_endpoint}/v2/evc/123"
1772 1
        response = await self.api_client.delete(url)
1773
        current_data = response.json()
1774
        expected_data = "circuit_id 123 not found"
1775
        assert current_data["description"] == expected_data
1776
        assert 404 == response.status_code
1777
1778 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
1779 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1780 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_uni_tags")
1781 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1782 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_current_flows")
1783 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1784 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1785 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1786 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1787 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1788 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1789 1
    async def test_delete_archived_evc(
1790
        self,
1791
        evc_as_dict_mock,
1792
        validate_mock,
1793
        mongo_controller_upsert_mock,
1794
        uni_from_dict_mock,
1795
        sched_add_mock,
1796
        evc_deploy_mock,
1797
        remove_current_flows_mock,
1798
        mock_use_uni,
1799
        mock_remove_tags,
1800
        mock_tags_equal,
1801
        mock_check_duplicate
1802
    ):
1803
        """Try to delete an archived EVC"""
1804 1
        self.napp.controller.loop = asyncio.get_running_loop()
1805 1
        validate_mock.return_value = True
1806 1
        mongo_controller_upsert_mock.return_value = True
1807 1
        sched_add_mock.return_value = True
1808 1
        evc_deploy_mock.return_value = True
1809 1
        mock_use_uni.return_value = True
1810 1
        mock_tags_equal.return_value = True
1811 1
        mock_check_duplicate.return_value = True
1812 1
        uni1 = create_autospec(UNI)
1813 1
        uni2 = create_autospec(UNI)
1814 1
        uni1.interface = create_autospec(Interface)
1815 1
        uni2.interface = create_autospec(Interface)
1816 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1817 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1818 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1819
1820 1
        payload1 = {
1821
            "name": "my evc1",
1822
            "uni_a": {
1823
                "interface_id": "00:00:00:00:00:00:00:01:1",
1824
                "tag": {"tag_type": 'vlan', "value": 80},
1825
            },
1826
            "uni_z": {
1827
                "interface_id": "00:00:00:00:00:00:00:02:2",
1828
                "tag": {"tag_type": 'vlan', "value": 1},
1829
            },
1830
            "dynamic_backup_path": True,
1831
        }
1832
1833 1
        evc_as_dict_mock.return_value = payload1
1834 1
        response = await self.api_client.post(
1835
            f"{self.base_endpoint}/v2/evc/",
1836
            json=payload1
1837
        )
1838 1
        assert 201 == response.status_code
1839 1
        assert len(self.napp.circuits) == 1
1840 1
        current_data = response.json()
1841 1
        circuit_id = current_data["circuit_id"]
1842 1
        self.napp.circuits[circuit_id].archive()
1843
1844 1
        response = await self.api_client.delete(
1845
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1846
        )
1847 1
        assert 200 == response.status_code
1848 1
        assert mock_remove_tags.call_count == 0
1849 1
        assert remove_current_flows_mock.call_count == 0
1850 1
        assert len(self.napp.circuits) == 0
1851
1852 1
        response = await self.api_client.delete(
1853
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1854
        )
1855
        current_data = response.json()
1856
        expected_data = f"circuit_id {circuit_id} not found"
1857
        assert current_data["description"] == expected_data
1858
        assert 404 == response.status_code
1859
        assert len(self.napp.circuits) == 0
1860
1861 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1862 1
    async def test_delete_circuit(self, emit_event_mock):
1863
        """Test delete_circuit"""
1864 1
        evc = MagicMock()
1865 1
        evc.archived = False
1866 1
        circuit_id = '1'
1867 1
        self.napp.circuits[circuit_id] = evc
1868 1
        response = await self.api_client.delete(
1869
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1870
        )
1871 1
        assert 200 == response.status_code
1872 1
        assert evc.deactivate.call_count == 1
1873 1
        assert evc.disable.call_count == 1
1874 1
        evc.remove_current_flows.assert_called_once_with(
1875
            sync=False
1876
        )
1877 1
        evc.remove_failover_flows.assert_called_once_with(
1878
            sync=False
1879
        )
1880 1
        assert evc.archive.call_count == 1
1881 1
        assert evc.remove_uni_tags.call_count == 1
1882 1
        assert evc.sync.call_count == 1
1883 1
        assert not self.napp.circuits
1884 1
        assert emit_event_mock.call_count == 1
1885
1886 1
    def test_handle_link_up(self):
1887
        """Test handle_link_up method."""
1888 1
        evc_mock = create_autospec(EVC)
1889 1
        evc_mock.service_level, evc_mock.creation_time = 0, 1
1890 1
        evc_mock.is_enabled = MagicMock(side_effect=[
1891
            True, False, True, True, True
1892
        ])
1893 1
        evc_mock.lock = MagicMock()
1894 1
        evc_mock.archived = False
1895 1
        evcs = [evc_mock, evc_mock, evc_mock]
1896 1
        event = KytosEvent(name="test", content={"link": "abc"})
1897 1
        self.napp.circuits = dict(zip(["1", "2", "3"], evcs))
1898 1
        self.napp.handle_link_up(event)
1899 1
        assert evc_mock.handle_link_up.call_count == 2
1900 1
        evc_mock.handle_link_up.assert_called_with("abc")
1901
1902 1
    @patch("time.sleep", return_value=None)
1903 1
    @patch("napps.kytos.mef_eline.utils.emit_event")
1904 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1905 1
    def test_handle_link_down(
1906
        self, emit_main_mock, emit_utils_mock, _
1907
    ):
1908
        """Test handle_link_down method."""
1909 1
        uni = create_autospec(UNI)
1910 1
        evc1 = MagicMock(id="1", service_level=0, creation_time=1,
1911
                         metadata="mock", _active="true", _enabled="true",
1912
                         uni_a=uni, uni_z=uni)
1913 1
        evc1.name = "name"
1914 1
        evc1.is_affected_by_link.return_value = True
1915 1
        evc1.handle_link_down.return_value = True
1916 1
        evc1.failover_path = None
1917 1
        evc2 = MagicMock(id="2", service_level=6, creation_time=1)
1918 1
        evc2.is_affected_by_link.return_value = False
1919 1
        evc2.is_failover_path_affected_by_link.return_value = True
1920 1
        evc2.as_dict.return_value = {"id": "2"}
1921 1
        evc3 = MagicMock(id="3", service_level=5, creation_time=1,
1922
                         metadata="mock", _active="true", _enabled="true",
1923
                         uni_a=uni, uni_z=uni)
1924 1
        evc3.name = "name"
1925 1
        evc3.is_affected_by_link.return_value = True
1926 1
        evc3.handle_link_down.return_value = True
1927 1
        evc3.failover_path = None
1928 1
        evc4 = MagicMock(id="4", service_level=4, creation_time=1,
1929
                         metadata="mock", _active="true", _enabled="true",
1930
                         uni_a=uni, uni_z=uni)
1931 1
        evc4.name = "name"
1932 1
        evc4.is_affected_by_link.return_value = True
1933 1
        evc4.is_failover_path_affected_by_link.return_value = False
1934 1
        evc4.failover_path = ["2"]
1935 1
        evc4.get_failover_flows.return_value = {
1936
            "2": ["flow1", "flow2"],
1937
            "3": ["flow3", "flow4", "flow5", "flow6"],
1938
        }
1939 1
        evc4.as_dict.return_value = {"id": "4"}
1940 1
        evc5 = MagicMock(id="5", service_level=7, creation_time=1)
1941 1
        evc5.is_affected_by_link.return_value = True
1942 1
        evc5.is_failover_path_affected_by_link.return_value = False
1943 1
        evc5.failover_path = ["3"]
1944 1
        evc5.get_failover_flows.return_value = {
1945
            "4": ["flow7", "flow8"],
1946
            "5": ["flow9", "flow10"],
1947
        }
1948 1
        evc5.as_dict.return_value = {"id": "5"}
1949 1
        evc6 = MagicMock(id="6", service_level=8, creation_time=1,
1950
                         metadata="mock", _active="true", _enabled="true",
1951
                         uni_a=uni, uni_z=uni)
1952 1
        evc6.name = "name"
1953 1
        evc6.is_affected_by_link.return_value = True
1954 1
        evc6.is_failover_path_affected_by_link.return_value = False
1955 1
        evc6.failover_path = ["3"]
1956 1
        evc6.get_failover_flows.side_effect = AttributeError("err")
1957 1
        link = MagicMock(id="123")
1958 1
        event = KytosEvent(name="test", content={"link": link})
1959 1
        self.napp.circuits = {"1": evc1, "2": evc2, "3": evc3, "4": evc4,
1960
                              "5": evc5, "6": evc6}
1961 1
        self.napp.handle_link_down(event)
1962
1963 1
        assert evc5.service_level > evc4.service_level
1964
        # evc5 batched flows should be sent first
1965 1
        emit_utils_mock.assert_has_calls([
1966
            call(
1967
                self.napp.controller,
1968
                context="kytos.flow_manager",
1969
                name="flows.install",
1970
                content={
1971
                    "dpid": "4",
1972
                    "flow_dict": {"flows": ["flow7", "flow8"]},
1973
                    'force': True,
1974
                }
1975
            ),
1976
            call(
1977
                self.napp.controller,
1978
                context="kytos.flow_manager",
1979
                name="flows.install",
1980
                content={
1981
                    "dpid": "5",
1982
                    "flow_dict": {"flows": ["flow9", "flow10"]},
1983
                    'force': True,
1984
                }
1985
            ),
1986
            call(
1987
                self.napp.controller,
1988
                context="kytos.flow_manager",
1989
                name="flows.install",
1990
                content={
1991
                    "dpid": "2",
1992
                    "flow_dict": {"flows": ["flow1", "flow2"]},
1993
                    'force': True,
1994
                }
1995
            ),
1996
            call(
1997
                self.napp.controller,
1998
                context="kytos.flow_manager",
1999
                name="flows.install",
2000
                content={
2001
                    "dpid": "3",
2002
                    "flow_dict": {
2003
                        "flows": ["flow3", "flow4", "flow5", "flow6"]
2004
                    },
2005
                    'force': True,
2006
                }
2007
            )
2008
        ])
2009 1
        event_name = "evc_affected_by_link_down"
2010 1
        assert evc3.service_level > evc1.service_level
2011
        # evc3 should be handled before evc1
2012 1
        emit_main_mock.assert_has_calls([
2013
            call(self.napp.controller, event_name, content={
2014
                "link": link,
2015
                "id": "6",
2016
                "evc_id": "6",
2017
                "name": "name",
2018
                "metadata": "mock",
2019
                "active": "true",
2020
                "enabled": "true",
2021
                "uni_a": uni.as_dict(),
2022
                "uni_z": uni.as_dict(),
2023
            }),
2024
            call(self.napp.controller, event_name, content={
2025
                "link": link,
2026
                "evc_id": "3",
2027
                "id": "3",
2028
                "name": "name",
2029
                "metadata": "mock",
2030
                "active": "true",
2031
                "enabled": "true",
2032
                "uni_a": uni.as_dict(),
2033
                "uni_z": uni.as_dict(),
2034
            }),
2035
            call(self.napp.controller, event_name, content={
2036
                "link": link,
2037
                "evc_id": "1",
2038
                "id": "1",
2039
                "name": "name",
2040
                "metadata": "mock",
2041
                "active": "true",
2042
                "enabled": "true",
2043
                "uni_a": uni.as_dict(),
2044
                "uni_z": uni.as_dict(),
2045
            }),
2046
        ])
2047 1
        self.napp.mongo_controller.update_evcs.assert_called_with(
2048
            [{"id": "5"}, {"id": "4"}, {"id": "2"}]
2049
        )
2050 1
        event_name = "failover_link_down"
2051 1
        assert emit_main_mock.call_args_list[0][0][1] == event_name
2052
2053 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2054 1
    def test_handle_evc_affected_by_link_down(self, emit_event_mock):
2055
        """Test handle_evc_affected_by_link_down method."""
2056 1
        uni = create_autospec(UNI)
2057 1
        evc1 = MagicMock(
2058
            id="1",
2059
            metadata="data_mocked",
2060
            _active="true",
2061
            _enabled="false",
2062
            uni_a=uni,
2063
            uni_z=uni,
2064
        )
2065 1
        evc1.name = "name_mocked"
2066 1
        evc1.handle_link_down.return_value = True
2067 1
        evc2 = MagicMock(
2068
            id="2",
2069
            metadata="mocked_data",
2070
            _active="false",
2071
            _enabled="true",
2072
            uni_a=uni,
2073
            uni_z=uni,
2074
        )
2075 1
        evc2.name = "mocked_name"
2076 1
        evc2.handle_link_down.return_value = False
2077 1
        self.napp.circuits = {"1": evc1, "2": evc2}
2078
2079 1
        event = KytosEvent(name="e1", content={
2080
            "evc_id": "3",
2081
            "link": MagicMock(),
2082
        })
2083 1
        self.napp.handle_evc_affected_by_link_down(event)
2084 1
        emit_event_mock.assert_not_called()
2085 1
        event.content["evc_id"] = "1"
2086 1
        self.napp.handle_evc_affected_by_link_down(event)
2087 1
        emit_event_mock.assert_called_with(
2088
            self.napp.controller, "redeployed_link_down", content={
2089
                "id": "1",
2090
                "evc_id": "1",
2091
                "name": "name_mocked",
2092
                "metadata": "data_mocked",
2093
                "active": "true",
2094
                "enabled": "false",
2095
                "uni_a": uni.as_dict(),
2096
                "uni_z": uni.as_dict(),
2097
            }
2098
        )
2099
2100 1
        event.content["evc_id"] = "2"
2101 1
        self.napp.handle_evc_affected_by_link_down(event)
2102 1
        emit_event_mock.assert_called_with(
2103
            self.napp.controller, "error_redeploy_link_down", content={
2104
                "evc_id": "2",
2105
                "id": "2",
2106
                "name": "mocked_name",
2107
                "metadata": "mocked_data",
2108
                "active": "false",
2109
                "enabled": "true",
2110
                "uni_a": uni.as_dict(),
2111
                "uni_z": uni.as_dict(),
2112
            }
2113
        )
2114
2115 1
    def test_cleanup_evcs_old_path(self, monkeypatch):
2116
        """Test handle_cleanup_evcs_old_path method."""
2117 1
        current_path, map_evc_content, emit_event = [
2118
            MagicMock(), MagicMock(), MagicMock()
2119
        ]
2120 1
        send_flows, merge_flows, create_flows = [
2121
            MagicMock(), MagicMock(), MagicMock()
2122
        ]
2123 1
        monkeypatch.setattr(
2124
            "napps.kytos.mef_eline.main.map_evc_event_content",
2125
            map_evc_content
2126
        )
2127 1
        monkeypatch.setattr(
2128
            "napps.kytos.mef_eline.main.emit_event",
2129
            emit_event
2130
        )
2131 1
        monkeypatch.setattr(
2132
            "napps.kytos.mef_eline.main.send_flow_mods_event",
2133
            send_flows
2134
        )
2135 1
        monkeypatch.setattr(
2136
            "napps.kytos.mef_eline.main.merge_flow_dicts",
2137
            merge_flows
2138
        )
2139 1
        monkeypatch.setattr(
2140
            "napps.kytos.mef_eline.main.prepare_delete_flow",
2141
            create_flows
2142
        )
2143 1
        merge_flows.return_value = ['1', '2']
2144 1
        evc1 = create_autospec(EVC, id="1", old_path=["1"],
2145
                               current_path=current_path, lock=MagicMock())
2146 1
        evc2 = create_autospec(EVC, id="2", old_path=["2"],
2147
                               current_path=current_path, lock=MagicMock())
2148 1
        evc3 = create_autospec(EVC, id="3", old_path=[],
2149
                               current_path=[], lock=MagicMock())
2150
2151 1
        event = KytosEvent(name="e1", content={"evcs": [evc1, evc2, evc3]})
2152 1
        assert evc1.old_path
2153 1
        assert evc2.old_path
2154 1
        self.napp.handle_cleanup_evcs_old_path(event)
2155 1
        evc1._prepare_nni_flows.assert_called_with(["1"])
2156 1
        evc1._prepare_uni_flows.assert_called_with(["1"], skip_in=True)
2157 1
        evc2._prepare_nni_flows.assert_called_with(["2"])
2158 1
        evc2._prepare_uni_flows.assert_called_with(["2"], skip_in=True)
2159 1
        evc3._prepare_nni_flows.assert_not_called()
2160 1
        evc3._prepare_uni_flows.assert_not_called()
2161 1
        assert create_flows.call_count == 4
2162 1
        assert emit_event.call_count == 1
2163 1
        assert emit_event.call_args[0][1] == "failover_old_path"
2164 1
        assert map_evc_content.call_args[1]['removed_flows'] == ['1', '2']
2165 1
        assert len(emit_event.call_args[1]["content"]) == 2
2166 1
        assert send_flows.call_count == 1
2167 1
        assert send_flows.call_args[0][1] == ['1', '2']
2168 1
        assert send_flows.call_args[0][2] == 'delete'
2169 1
        assert merge_flows.call_count == 4
2170 1
        assert not evc1.old_path
2171 1
        assert not evc2.old_path
2172
2173 1
    async def test_add_metadata(self):
2174
        """Test method to add metadata"""
2175 1
        self.napp.controller.loop = asyncio.get_running_loop()
2176 1
        evc_mock = create_autospec(EVC)
2177 1
        evc_mock.metadata = {}
2178 1
        evc_mock.id = 1234
2179 1
        self.napp.circuits = {"1234": evc_mock}
2180
2181 1
        payload = {"metadata1": 1, "metadata2": 2}
2182 1
        response = await self.api_client.post(
2183
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2184
            json=payload
2185
        )
2186
2187 1
        assert response.status_code == 201
2188 1
        evc_mock.extend_metadata.assert_called_with(payload)
2189
2190 1
    async def test_add_metadata_malformed_json(self):
2191
        """Test method to add metadata with a malformed json"""
2192 1
        self.napp.controller.loop = asyncio.get_running_loop()
2193 1
        payload = b'{"metadata1": 1, "metadata2": 2,}'
2194 1
        response = await self.api_client.post(
2195
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2196
            content=payload,
2197
            headers={"Content-Type": "application/json"}
2198
        )
2199
2200
        assert response.status_code == 400
2201
        assert "body contains invalid API" in response.json()["description"]
2202
2203 1
    async def test_add_metadata_no_body(self):
2204
        """Test method to add metadata with no body"""
2205 1
        self.napp.controller.loop = asyncio.get_running_loop()
2206 1
        response = await self.api_client.post(
2207
            f"{self.base_endpoint}/v2/evc/1234/metadata"
2208
        )
2209
        assert response.status_code == 400
2210
        assert response.json()["description"] == \
2211
            "Missing required request body"
2212
2213 1
    async def test_add_metadata_no_evc(self):
2214
        """Test method to add metadata with no evc"""
2215 1
        self.napp.controller.loop = asyncio.get_running_loop()
2216 1
        payload = {"metadata1": 1, "metadata2": 2}
2217 1
        response = await self.api_client.post(
2218
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2219
            json=payload,
2220
        )
2221
        assert response.status_code == 404
2222
        assert response.json()["description"] == \
2223
            "circuit_id 1234 not found."
2224
2225 1
    async def test_add_metadata_wrong_content_type(self):
2226
        """Test method to add metadata with wrong content type"""
2227 1
        self.napp.controller.loop = asyncio.get_running_loop()
2228 1
        payload = {"metadata1": 1, "metadata2": 2}
2229 1
        response = await self.api_client.post(
2230
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2231
            data=payload,
2232
            headers={"Content-Type": "application/xml"}
2233
        )
2234
        assert response.status_code == 415
2235
        assert "application/xml" in response.json()["description"]
2236
2237 1
    async def test_get_metadata(self):
2238
        """Test method to get metadata"""
2239 1
        evc_mock = create_autospec(EVC)
2240 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2241 1
        evc_mock.id = 1234
2242 1
        self.napp.circuits = {"1234": evc_mock}
2243
2244 1
        response = await self.api_client.get(
2245
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2246
        )
2247 1
        assert response.status_code == 200
2248 1
        assert response.json() == {"metadata": evc_mock.metadata}
2249
2250 1
    async def test_delete_metadata(self):
2251
        """Test method to delete metadata"""
2252 1
        evc_mock = create_autospec(EVC)
2253 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2254 1
        evc_mock.id = 1234
2255 1
        self.napp.circuits = {"1234": evc_mock}
2256
2257 1
        response = await self.api_client.delete(
2258
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2259
        )
2260 1
        assert response.status_code == 200
2261
2262 1
    async def test_delete_metadata_no_evc(self):
2263
        """Test method to delete metadata with no evc"""
2264 1
        response = await self.api_client.delete(
2265
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2266
        )
2267
        assert response.status_code == 404
2268
        assert response.json()["description"] == \
2269
            "circuit_id 1234 not found."
2270
2271 1
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
2272 1
    def test_load_all_evcs(self, load_evc_mock):
2273
        """Test load_evcs method"""
2274 1
        mock_circuits = {
2275
            'circuits': {
2276
                1: 'circuit_1',
2277
                2: 'circuit_2',
2278
                3: 'circuit_3',
2279
                4: 'circuit_4'
2280
            }
2281
        }
2282 1
        self.napp.mongo_controller.get_circuits.return_value = mock_circuits
2283 1
        self.napp.circuits = {2: 'circuit_2', 3: 'circuit_3'}
2284 1
        self.napp.load_all_evcs()
2285 1
        load_evc_mock.assert_has_calls([call('circuit_1'), call('circuit_4')])
2286 1
        assert self.napp.controller.buffers.app.put.call_count > 1
2287 1
        call_args = self.napp.controller.buffers.app.put.call_args[0]
2288 1
        assert call_args[0].name == "kytos/mef_eline.evcs_loaded"
2289 1
        assert dict(call_args[0].content) == mock_circuits["circuits"]
2290 1
        timeout_d = {"timeout": 1}
2291 1
        assert self.napp.controller.buffers.app.put.call_args[1] == timeout_d
2292
2293 1
    @patch('napps.kytos.mef_eline.main.Main._evc_from_dict')
2294 1
    def test_load_evc(self, evc_from_dict_mock):
2295
        """Test _load_evc method"""
2296
        # pylint: disable=protected-access
2297
        # case 1: early return with ValueError exception
2298 1
        evc_from_dict_mock.side_effect = ValueError("err")
2299 1
        evc_dict = MagicMock()
2300 1
        assert not self.napp._load_evc(evc_dict)
2301
2302
        # case 2: early return with KytosTagError exception
2303 1
        evc_from_dict_mock.side_effect = KytosTagError("")
2304 1
        assert not self.napp._load_evc(evc_dict)
2305
2306
        # case 3: archived evc
2307 1
        evc = MagicMock()
2308 1
        evc.archived = True
2309 1
        evc_from_dict_mock.side_effect = None
2310 1
        evc_from_dict_mock.return_value = evc
2311 1
        assert not self.napp._load_evc(evc_dict)
2312
2313
        # case 4: success creating
2314 1
        evc.archived = False
2315 1
        evc.id = 1
2316 1
        self.napp.sched = MagicMock()
2317
2318 1
        result = self.napp._load_evc(evc_dict)
2319 1
        assert result == evc
2320 1
        self.napp.sched.add.assert_called_with(evc)
2321 1
        assert self.napp.circuits[1] == evc
2322
2323 1
    def test_handle_flow_mod_error(self):
2324
        """Test handle_flow_mod_error method"""
2325 1
        flow = MagicMock()
2326 1
        flow.cookie = 0xaa00000000000011
2327 1
        event = MagicMock()
2328 1
        event.content = {'flow': flow, 'error_command': 'add'}
2329 1
        evc = create_autospec(EVC)
2330 1
        evc.remove_current_flows = MagicMock()
2331 1
        evc.lock = MagicMock()
2332 1
        self.napp.circuits = {"00000000000011": evc}
2333 1
        self.napp.handle_flow_mod_error(event)
2334 1
        evc.remove_current_flows.assert_called_once()
2335
2336 1
    @patch("kytos.core.Controller.get_interface_by_id")
2337 1
    def test_uni_from_dict(self, _get_interface_by_id_mock):
2338
        """Test _uni_from_dict method."""
2339
        # pylint: disable=protected-access
2340
        # case1: early return on empty dict
2341 1
        assert not self.napp._uni_from_dict(None)
2342
2343
        # case2: invalid interface raises ValueError
2344 1
        _get_interface_by_id_mock.return_value = None
2345 1
        uni_dict = {
2346
            "interface_id": "00:01:1",
2347
            "tag": {"tag_type": 'vlan', "value": 81},
2348
        }
2349 1
        with pytest.raises(ValueError):
2350 1
            self.napp._uni_from_dict(uni_dict)
2351
2352
        # case3: success creation
2353 1
        uni_mock = get_uni_mocked(switch_id="00:01")
2354 1
        _get_interface_by_id_mock.return_value = uni_mock.interface
2355 1
        uni = self.napp._uni_from_dict(uni_dict)
2356 1
        assert uni == uni_mock
2357
2358
        # case4: success creation of tag list
2359 1
        uni_dict["tag"]["value"] = [[1, 10]]
2360 1
        uni = self.napp._uni_from_dict(uni_dict)
2361 1
        assert isinstance(uni.user_tag, TAGRange)
2362
2363
        # case5: success creation without tag
2364 1
        uni_mock.user_tag = None
2365 1
        del uni_dict["tag"]
2366 1
        uni = self.napp._uni_from_dict(uni_dict)
2367 1
        assert uni == uni_mock
2368
2369 1
    def test_handle_flow_delete(self):
2370
        """Test handle_flow_delete method"""
2371 1
        flow = MagicMock()
2372 1
        flow.cookie = 0xaa00000000000011
2373 1
        event = MagicMock()
2374 1
        event.content = {'flow': flow}
2375 1
        evc = create_autospec(EVC)
2376 1
        evc.set_flow_removed_at = MagicMock()
2377 1
        self.napp.circuits = {"00000000000011": evc}
2378 1
        self.napp.handle_flow_delete(event)
2379 1
        evc.set_flow_removed_at.assert_called_once()
2380
2381 1 View Code Duplication
    async def test_add_bulk_metadata(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2382
        """Test add_bulk_metadata method"""
2383 1
        self.napp.controller.loop = asyncio.get_running_loop()
2384 1
        evc_mock = create_autospec(EVC)
2385 1
        evc_mock.id = 1234
2386 1
        self.napp.circuits = {"1234": evc_mock}
2387 1
        payload = {
2388
            "circuit_ids": ["1234"],
2389
            "metadata1": 1,
2390
            "metadata2": 2
2391
        }
2392 1
        response = await self.api_client.post(
2393
            f"{self.base_endpoint}/v2/evc/metadata",
2394
            json=payload
2395
        )
2396 1
        assert response.status_code == 201
2397 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2398 1
        ids = payload.pop("circuit_ids")
2399 1
        assert args[0] == ids
2400 1
        assert args[1] == payload
2401 1
        assert args[2] == "add"
2402 1
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2403 1
        assert calls == 1
2404 1
        evc_mock.extend_metadata.assert_called_with(payload)
2405
2406 1
    async def test_add_bulk_metadata_empty_list(self):
2407
        """Test add_bulk_metadata method empty list"""
2408 1
        self.napp.controller.loop = asyncio.get_running_loop()
2409 1
        evc_mock = create_autospec(EVC)
2410 1
        evc_mock.id = 1234
2411 1
        self.napp.circuits = {"1234": evc_mock}
2412 1
        payload = {
2413
            "circuit_ids": [],
2414
            "metadata1": 1,
2415
            "metadata2": 2
2416
        }
2417 1
        response = await self.api_client.post(
2418
            f"{self.base_endpoint}/v2/evc/metadata",
2419
            json=payload
2420
        )
2421
        assert response.status_code == 400
2422
        assert "invalid" in response.json()["description"]
2423
2424 1
    async def test_add_bulk_metadata_no_id(self):
2425
        """Test add_bulk_metadata with unknown evc id"""
2426 1
        self.napp.controller.loop = asyncio.get_running_loop()
2427 1
        evc_mock = create_autospec(EVC)
2428 1
        evc_mock.id = 1234
2429 1
        self.napp.circuits = {"1234": evc_mock}
2430 1
        payload = {
2431
            "circuit_ids": ["1234", "4567"]
2432
        }
2433 1
        response = await self.api_client.post(
2434
            f"{self.base_endpoint}/v2/evc/metadata",
2435
            json=payload
2436
        )
2437
        assert response.status_code == 404
2438
2439 1
    async def test_add_bulk_metadata_no_circuits(self):
2440
        """Test add_bulk_metadata without circuit_ids"""
2441 1
        self.napp.controller.loop = asyncio.get_running_loop()
2442 1
        evc_mock = create_autospec(EVC)
2443 1
        evc_mock.id = 1234
2444 1
        self.napp.circuits = {"1234": evc_mock}
2445 1
        payload = {
2446
            "metadata": "data"
2447
        }
2448 1
        response = await self.api_client.post(
2449
            f"{self.base_endpoint}/v2/evc/metadata",
2450
            json=payload
2451
        )
2452
        assert response.status_code == 400
2453
2454 1 View Code Duplication
    async def test_delete_bulk_metadata(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2455
        """Test delete_metadata method"""
2456 1
        self.napp.controller.loop = asyncio.get_running_loop()
2457 1
        evc_mock = create_autospec(EVC)
2458 1
        evc_mock.id = 1234
2459 1
        self.napp.circuits = {"1234": evc_mock}
2460 1
        payload = {
2461
            "circuit_ids": ["1234"]
2462
        }
2463 1
        response = await self.api_client.request(
2464
            "DELETE",
2465
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2466
            json=payload
2467
        )
2468 1
        assert response.status_code == 200
2469 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2470 1
        assert args[0] == payload["circuit_ids"]
2471 1
        assert args[1] == {"metadata1": ""}
2472 1
        assert args[2] == "del"
2473 1
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2474 1
        assert calls == 1
2475 1
        assert evc_mock.remove_metadata.call_count == 1
2476
2477 1
    async def test_delete_bulk_metadata_error(self):
2478
        """Test bulk_delete_metadata with ciruit erroring"""
2479 1
        self.napp.controller.loop = asyncio.get_running_loop()
2480 1
        evc_mock = create_autospec(EVC)
2481 1
        evcs = [evc_mock, evc_mock]
2482 1
        self.napp.circuits = dict(zip(["1", "2"], evcs))
2483 1
        payload = {"circuit_ids": ["1", "2", "3"]}
2484 1
        response = await self.api_client.request(
2485
            "DELETE",
2486
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2487
            json=payload
2488
        )
2489
        assert response.status_code == 404, response.data
2490
        assert response.json()["description"] == ["3"]
2491
2492 1
    async def test_use_uni_tags(self):
2493
        """Test _use_uni_tags"""
2494 1
        self.napp.controller.loop = asyncio.get_running_loop()
2495 1
        evc_mock = create_autospec(EVC)
2496 1
        evc_mock.uni_a = "uni_a_mock"
2497 1
        evc_mock.uni_z = "uni_z_mock"
2498 1
        self.napp._use_uni_tags(evc_mock)
2499 1
        assert evc_mock._use_uni_vlan.call_count == 2
2500 1
        assert evc_mock._use_uni_vlan.call_args[0][0] == evc_mock.uni_z
2501
2502
        # One UNI tag is not available
2503 1
        evc_mock._use_uni_vlan.side_effect = [KytosTagError(""), None]
2504 1
        with pytest.raises(KytosTagError):
2505 1
            self.napp._use_uni_tags(evc_mock)
2506 1
        assert evc_mock._use_uni_vlan.call_count == 3
2507 1
        assert evc_mock.make_uni_vlan_available.call_count == 0
2508
2509 1
        evc_mock._use_uni_vlan.side_effect = [None, KytosTagError("")]
2510 1
        with pytest.raises(KytosTagError):
2511 1
            self.napp._use_uni_tags(evc_mock)
2512 1
        assert evc_mock._use_uni_vlan.call_count == 5
2513 1
        assert evc_mock.make_uni_vlan_available.call_count == 1
2514
2515 1
    def test_check_no_tag_duplication(self):
2516
        """Test _check_no_tag_duplication"""
2517 1
        evc = MagicMock()
2518 1
        evc.check_no_tag_duplicate = MagicMock()
2519 1
        evc.archived = False
2520 1
        evc.id = "1"
2521 1
        self.napp.circuits = {"1": evc}
2522 1
        evc_id = "2"
2523 1
        uni_a = get_uni_mocked(valid=True)
2524 1
        uni_z = get_uni_mocked(valid=True)
2525 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2526 1
        assert evc.check_no_tag_duplicate.call_count == 0
2527
2528 1
        uni_a.user_tag = None
2529 1
        uni_z.user_tag = None
2530 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2531 1
        assert evc.check_no_tag_duplicate.call_count == 2
2532
2533 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, None)
2534 1
        assert evc.check_no_tag_duplicate.call_count == 3
2535
2536 1
        self.napp._check_no_tag_duplication(evc_id, None, None)
2537 1
        assert evc.check_no_tag_duplicate.call_count == 3
2538
2539 1
    @patch("napps.kytos.mef_eline.main.time")
2540 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_up")
2541 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_down")
2542 1
    def test_handle_on_interface_link_change(
2543
        self,
2544
        mock_down,
2545
        mock_up,
2546
        mock_time
2547
    ):
2548
        """Test handle_on_interface_link_change"""
2549 1
        mock_time.sleep.return_value = True
2550 1
        mock_intf = Mock()
2551 1
        mock_intf.id = "mock_intf"
2552
2553
        # Created/link_up
2554 1
        name = '.*.switch.interface.created'
2555 1
        content = {"interface": mock_intf}
2556 1
        event = KytosEvent(name=name, content=content)
2557 1
        self.napp.handle_on_interface_link_change(event)
2558 1
        assert mock_down.call_count == 0
2559 1
        assert mock_up.call_count == 1
2560
2561
        # Deleted/link_down
2562 1
        name = '.*.switch.interface.deleted'
2563 1
        event = KytosEvent(name=name, content=content)
2564 1
        self.napp.handle_on_interface_link_change(event)
2565 1
        assert mock_down.call_count == 1
2566 1
        assert mock_up.call_count == 1
2567
2568
        # Event delay
2569 1
        self.napp._intf_events[mock_intf.id]["last_acquired"] = "mock_time"
2570 1
        for _ in range(1, 6):
2571 1
            self.napp.handle_on_interface_link_change(event)
2572 1
        assert mock_down.call_count == 1
2573 1
        assert mock_up.call_count == 1
2574
2575 1
        self.napp._intf_events[mock_intf.id].pop("last_acquired")
2576 1
        self.napp.handle_on_interface_link_change(event)
2577 1
        assert mock_down.call_count == 2
2578 1
        assert mock_up.call_count == 1
2579
2580
        # Out of order event
2581 1
        event = KytosEvent(name=name, content=content)
2582 1
        self.napp._intf_events[mock_intf.id]["event"] = Mock(timestamp=now())
2583
2584 1
        self.napp.handle_on_interface_link_change(event)
2585 1
        assert mock_down.call_count == 2
2586
        assert mock_up.call_count == 1
2587