Passed
Pull Request — master (#583)
by
unknown
04:16
created

TestMain.test_update_circuit_invalid_path()   B

Complexity

Conditions 1

Size

Total Lines 84
Code Lines 69

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 38
CRAP Score 1.0008

Importance

Changes 0
Metric Value
cc 1
eloc 69
nop 12
dl 0
loc 84
ccs 38
cts 42
cp 0.9048
crap 1.0008
rs 8.0145
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
"""Module to test the main napp file."""
2 1
import asyncio
3 1
from unittest.mock import (AsyncMock, MagicMock, Mock, call,
4
                           create_autospec, patch)
5
6 1
import pytest
7 1
from kytos.lib.helpers import get_controller_mock, get_test_client
8 1
from kytos.core.helpers import now
9 1
from kytos.core.common import EntityStatus
10 1
from kytos.core.events import KytosEvent
11 1
from kytos.core.exceptions import KytosTagError
12 1
from kytos.core.interface import TAGRange, UNI, Interface
13 1
from napps.kytos.mef_eline.exceptions import InvalidPath
14 1
from napps.kytos.mef_eline.models import EVC
15 1
from napps.kytos.mef_eline.tests.helpers import get_uni_mocked
16
17
18 1
async def test_on_table_enabled():
19
    """Test on_table_enabled"""
20
    # pylint: disable=import-outside-toplevel
21 1
    from napps.kytos.mef_eline.main import Main
22 1
    controller = get_controller_mock()
23 1
    controller.buffers.app.aput = AsyncMock()
24 1
    Main.get_eline_controller = MagicMock()
25 1
    napp = Main(controller)
26
27
    # Succesfully setting table groups
28 1
    content = {"mef_eline": {"epl": 2}}
29 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
30
                       content=content)
31 1
    await napp.on_table_enabled(event)
32 1
    assert napp.table_group["epl"] == 2
33 1
    assert napp.table_group["evpl"] == 0
34 1
    assert controller.buffers.app.aput.call_count == 1
35
36
    # Failure at setting table groups
37 1
    content = {"mef_eline": {"unknown": 123}}
38 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
39
                       content=content)
40 1
    await napp.on_table_enabled(event)
41 1
    assert controller.buffers.app.aput.call_count == 1
42
43
    # Failure with early return
44 1
    content = {}
45 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
46
                       content=content)
47 1
    await napp.on_table_enabled(event)
48 1
    assert controller.buffers.app.aput.call_count == 1
49
50
51
# pylint: disable=too-many-public-methods, too-many-lines
52
# pylint: disable=too-many-arguments,too-many-locals
53 1
class TestMain:
54
    """Test the Main class."""
55
56 1
    def setup_method(self):
57
        """Execute steps before each tests.
58
59
        Set the server_name_url_url from kytos/mef_eline
60
        """
61
62
        # The decorator run_on_thread is patched, so methods that listen
63
        # for events do not run on threads while tested.
64
        # Decorators have to be patched before the methods that are
65
        # decorated with them are imported.
66 1
        patch("kytos.core.helpers.run_on_thread", lambda x: x).start()
67
        # pylint: disable=import-outside-toplevel
68 1
        from napps.kytos.mef_eline.main import Main
69 1
        Main.get_eline_controller = MagicMock()
70 1
        controller = get_controller_mock()
71 1
        self.napp = Main(controller)
72 1
        self.api_client = get_test_client(controller, self.napp)
73 1
        self.base_endpoint = "kytos/mef_eline"
74
75 1
    def test_get_event_listeners(self):
76
        """Verify all event listeners registered."""
77 1
        expected_events = [
78
            "kytos/core.shutdown",
79
            "kytos/core.shutdown.kytos/mef_eline",
80
            "kytos/topology.link_up",
81
            "kytos/topology.link_down",
82
        ]
83 1
        actual_events = self.napp.listeners()
84
85 1
        for _event in expected_events:
86 1
            assert _event in actual_events, _event
87
88 1
    @patch('napps.kytos.mef_eline.main.log')
89 1
    @patch('napps.kytos.mef_eline.main.Main.execute_consistency')
90 1
    def test_execute(self, mock_execute_consistency, mock_log):
91
        """Test execute."""
92 1
        self.napp.execution_rounds = 0
93 1
        self.napp.execute()
94 1
        mock_execute_consistency.assert_called()
95 1
        assert mock_log.debug.call_count == 2
96
97
        # Test locked should return
98 1
        mock_execute_consistency.call_count = 0
99 1
        mock_log.info.call_count = 0
100
        # pylint: disable=protected-access
101 1
        self.napp._lock = MagicMock()
102 1
        self.napp._lock.locked.return_value = True
103
        # pylint: enable=protected-access
104 1
        self.napp.execute()
105 1
        mock_execute_consistency.assert_not_called()
106 1
        mock_log.info.assert_not_called()
107
108 1
    @patch('napps.kytos.mef_eline.main.settings')
109 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
110 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_list_traces")
111 1
    def test_execute_consistency(self, mock_check_list_traces, *args):
112
        """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_with(
832
            sync=False, return_path=True
833
        )
834 1
        assert response.status_code == 202, response.data
835
836 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
837 1
        url = url + "?try_avoid_same_s_vlan=false"
838 1
        response = await self.api_client.patch(url)
839 1
        evc1.remove_current_flows.assert_called_with(
840
            sync=False, return_path=False
841
        )
842
843 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
844 1
        url = url + "?try_avoid_same_s_vlan=True"
845 1
        response = await self.api_client.patch(url)
846 1
        evc1.remove_current_flows.assert_called_with(
847
            sync=False, return_path=True
848
        )
849
850 1
    async def test_redeploy_evc_disabled(self):
851
        """Test endpoint to redeploy an EVC."""
852 1
        evc1 = MagicMock()
853 1
        evc1.is_enabled.return_value = False
854 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
855 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
856 1
        response = await self.api_client.patch(url)
857 1
        evc1.remove_failover_flows.assert_not_called()
858 1
        evc1.remove_current_flows.assert_not_called()
859 1
        assert response.status_code == 409, response.data
860
861 1
    async def test_redeploy_evc_deleted(self):
862
        """Test endpoint to redeploy an EVC."""
863 1
        evc1 = MagicMock()
864 1
        evc1.is_enabled.return_value = True
865 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
866 1
        url = f"{self.base_endpoint}/v2/evc/3/redeploy"
867 1
        response = await self.api_client.patch(url)
868
        assert response.status_code == 404, response.data
869
870 1
    async def test_list_schedules__no_data_stored(self):
871
        """Test if list circuits return all circuits stored."""
872 1
        self.napp.mongo_controller.get_circuits.return_value = {"circuits": {}}
873
874 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
875
876 1
        response = await self.api_client.get(url)
877 1
        assert response.status_code == 200
878 1
        assert not response.json()
879
880 1
    def _add_mongodb_schedule_data(self, data_mock):
881
        """Add schedule data to mongodb mock object."""
882 1
        circuits = {"circuits": {}}
883 1
        payload_1 = {
884
            "id": "aa:aa:aa",
885
            "name": "my evc1",
886
            "uni_a": {
887
                "interface_id": "00:00:00:00:00:00:00:01:1",
888
                "tag": {"tag_type": 'vlan', "value": 80},
889
            },
890
            "uni_z": {
891
                "interface_id": "00:00:00:00:00:00:00:02:2",
892
                "tag": {"tag_type": 'vlan', "value": 1},
893
            },
894
            "circuit_scheduler": [
895
                {"id": "1", "frequency": "* * * * *", "action": "create"},
896
                {"id": "2", "frequency": "1 * * * *", "action": "remove"},
897
            ],
898
        }
899 1
        circuits["circuits"].update({"aa:aa:aa": payload_1})
900 1
        payload_2 = {
901
            "id": "bb:bb:bb",
902
            "name": "my second evc2",
903
            "uni_a": {
904
                "interface_id": "00:00:00:00:00:00:00:01:2",
905
                "tag": {"tag_type": 'vlan', "value": 90},
906
            },
907
            "uni_z": {
908
                "interface_id": "00:00:00:00:00:00:00:03:2",
909
                "tag": {"tag_type": 'vlan', "value": 100},
910
            },
911
            "circuit_scheduler": [
912
                {"id": "3", "frequency": "1 * * * *", "action": "create"},
913
                {"id": "4", "frequency": "2 * * * *", "action": "remove"},
914
            ],
915
        }
916 1
        circuits["circuits"].update({"bb:bb:bb": payload_2})
917 1
        payload_3 = {
918
            "id": "cc:cc:cc",
919
            "name": "my third evc3",
920
            "uni_a": {
921
                "interface_id": "00:00:00:00:00:00:00:03:1",
922
                "tag": {"tag_type": 'vlan', "value": 90},
923
            },
924
            "uni_z": {
925
                "interface_id": "00:00:00:00:00:00:00:04:2",
926
                "tag": {"tag_type": 'vlan', "value": 100},
927
            },
928
        }
929 1
        circuits["circuits"].update({"cc:cc:cc": payload_3})
930
        # Add one circuit to the mongodb.
931 1
        data_mock.return_value = circuits
932
933 1
    async def test_list_schedules_from_mongodb(self):
934
        """Test if list circuits return specific circuits stored."""
935 1
        self._add_mongodb_schedule_data(
936
            self.napp.mongo_controller.get_circuits
937
        )
938
939 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
940
941
        # Call URL
942 1
        response = await self.api_client.get(url)
943
        # Expected JSON data from response
944 1
        expected = [
945
            {
946
                "circuit_id": "aa:aa:aa",
947
                "schedule": {
948
                    "action": "create",
949
                    "frequency": "* * * * *",
950
                    "id": "1",
951
                },
952
                "schedule_id": "1",
953
            },
954
            {
955
                "circuit_id": "aa:aa:aa",
956
                "schedule": {
957
                    "action": "remove",
958
                    "frequency": "1 * * * *",
959
                    "id": "2",
960
                },
961
                "schedule_id": "2",
962
            },
963
            {
964
                "circuit_id": "bb:bb:bb",
965
                "schedule": {
966
                    "action": "create",
967
                    "frequency": "1 * * * *",
968
                    "id": "3",
969
                },
970
                "schedule_id": "3",
971
            },
972
            {
973
                "circuit_id": "bb:bb:bb",
974
                "schedule": {
975
                    "action": "remove",
976
                    "frequency": "2 * * * *",
977
                    "id": "4",
978
                },
979
                "schedule_id": "4",
980
            },
981
        ]
982
983 1
        assert response.status_code == 200
984 1
        assert expected == response.json()
985
986 1
    async def test_get_specific_schedule_from_mongodb(self):
987
        """Test get schedules from a circuit."""
988 1
        self._add_mongodb_schedule_data(
989
            self.napp.mongo_controller.get_circuits
990
        )
991
992 1
        requested_circuit_id = "bb:bb:bb"
993 1
        evc = self.napp.mongo_controller.get_circuits()
994 1
        evc = evc["circuits"][requested_circuit_id]
995 1
        self.napp.mongo_controller.get_circuit.return_value = evc
996 1
        url = f"{self.base_endpoint}/v2/evc/{requested_circuit_id}"
997
998
        # Call URL
999 1
        response = await self.api_client.get(url)
1000
1001
        # Expected JSON data from response
1002 1
        expected = [
1003
            {"action": "create", "frequency": "1 * * * *", "id": "3"},
1004
            {"action": "remove", "frequency": "2 * * * *", "id": "4"},
1005
        ]
1006
1007 1
        assert response.status_code == 200
1008 1
        assert expected == response.json()["circuit_scheduler"]
1009
1010 1
    async def test_get_specific_schedules_from_mongodb_not_found(self):
1011
        """Test get specific schedule ID that does not exist."""
1012 1
        requested_id = "blah"
1013 1
        self.napp.mongo_controller.get_circuit.return_value = None
1014 1
        url = f"{self.base_endpoint}/v2/evc/{requested_id}"
1015
1016
        # Call URL
1017 1
        response = await self.api_client.get(url)
1018
1019
        expected = "circuit_id blah not found"
1020
        # Assert response not found
1021
        assert response.status_code == 404
1022
        assert expected == response.json()["description"]
1023
1024 1
    def _uni_from_dict_side_effect(self, uni_dict):
1025 1
        interface_id = uni_dict.get("interface_id")
1026 1
        tag_dict = uni_dict.get("tag")
1027 1
        interface = Interface(interface_id, "0", MagicMock(id="1"))
1028 1
        return UNI(interface, tag_dict)
1029
1030 1
    @patch("apscheduler.schedulers.background.BackgroundScheduler.add_job")
1031 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1032 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1033 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1034 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1035 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1036 1
    async def test_create_schedule(
1037
        self,
1038
        validate_mock,
1039
        evc_as_dict_mock,
1040
        mongo_controller_upsert_mock,
1041
        uni_from_dict_mock,
1042
        sched_add_mock,
1043
        scheduler_add_job_mock
1044
    ):
1045
        """Test create a circuit schedule."""
1046 1
        self.napp.controller.loop = asyncio.get_running_loop()
1047 1
        validate_mock.return_value = True
1048 1
        mongo_controller_upsert_mock.return_value = True
1049 1
        uni_from_dict_mock.side_effect = self._uni_from_dict_side_effect
1050 1
        evc_as_dict_mock.return_value = {}
1051 1
        sched_add_mock.return_value = True
1052
1053 1
        self._add_mongodb_schedule_data(
1054
            self.napp.mongo_controller.get_circuits
1055
        )
1056
1057 1
        requested_id = "bb:bb:bb"
1058 1
        url = f"{self.base_endpoint}/v2/evc/schedule/"
1059
1060 1
        payload = {
1061
            "circuit_id": requested_id,
1062
            "schedule": {"frequency": "1 * * * *", "action": "create"},
1063
            "metadata": {"metadata1": "test_data"},
1064
        }
1065
1066
        # Call URL
1067 1
        response = await self.api_client.post(url, json=payload)
1068 1
        response_json = response.json()
1069
1070 1
        assert response.status_code == 201
1071 1
        scheduler_add_job_mock.assert_called_once()
1072 1
        mongo_controller_upsert_mock.assert_called_once()
1073 1
        assert payload["schedule"]["frequency"] == response_json["frequency"]
1074 1
        assert payload["schedule"]["action"] == response_json["action"]
1075 1
        assert response_json["id"] is not None
1076
1077
        # Case 2: there is no schedule
1078 1
        payload = {
1079
              "circuit_id": "cc:cc:cc",
1080
              "schedule": {
1081
                "frequency": "1 * * * *",
1082
                "action": "create"
1083
              }
1084
            }
1085 1
        response = await self.api_client.post(url, json=payload)
1086 1
        assert response.status_code == 201
1087
1088 1
    async def test_create_schedule_invalid_request(self):
1089
        """Test create schedule API with invalid request."""
1090 1
        self.napp.controller.loop = asyncio.get_running_loop()
1091 1
        evc1 = MagicMock()
1092 1
        self.napp.circuits = {'bb:bb:bb': evc1}
1093 1
        url = f'{self.base_endpoint}/v2/evc/schedule/'
1094
1095
        # case 1: empty post
1096 1
        response = await self.api_client.post(url, json={})
1097
        assert response.status_code == 400
1098
1099
        # case 2: not a dictionary
1100
        payload = []
1101
        response = await self.api_client.post(url, json=payload)
1102
        assert response.status_code == 400
1103
1104
        # case 3: missing circuit id
1105
        payload = {
1106
            "schedule": {
1107
                "frequency": "1 * * * *",
1108
                "action": "create"
1109
            }
1110
        }
1111
        response = await self.api_client.post(url, json=payload)
1112
        assert response.status_code == 400
1113
1114
        # case 4: missing schedule
1115
        payload = {
1116
            "circuit_id": "bb:bb:bb"
1117
        }
1118
        response = await self.api_client.post(url, json=payload)
1119
        assert response.status_code == 400
1120
1121
        # case 5: invalid circuit
1122
        payload = {
1123
            "circuit_id": "xx:xx:xx",
1124
            "schedule": {
1125
                "frequency": "1 * * * *",
1126
                "action": "create"
1127
            }
1128
        }
1129
        response = await self.api_client.post(url, json=payload)
1130
        assert response.status_code == 404
1131
1132
        # case 6: invalid json
1133
        response = await self.api_client.post(url, json="test")
1134
        assert response.status_code == 400
1135
1136 1
    @patch('apscheduler.schedulers.background.BackgroundScheduler.remove_job')
1137 1
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1138 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1139 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1140 1
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1141 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1142 1
    async def test_update_schedule(
1143
        self,
1144
        validate_mock,
1145
        evc_as_dict_mock,
1146
        mongo_controller_upsert_mock,
1147
        uni_from_dict_mock,
1148
        sched_add_mock,
1149
        scheduler_remove_job_mock
1150
    ):
1151
        """Test create a circuit schedule."""
1152 1
        self.napp.controller.loop = asyncio.get_running_loop()
1153 1
        mongo_payload_1 = {
1154
            "circuits": {
1155
                "aa:aa:aa": {
1156
                    "id": "aa:aa:aa",
1157
                    "name": "my evc1",
1158
                    "uni_a": {
1159
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1160
                        "tag": {"tag_type": 'vlan', "value": 80},
1161
                    },
1162
                    "uni_z": {
1163
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1164
                        "tag": {"tag_type": 'vlan', "value": 1},
1165
                    },
1166
                    "circuit_scheduler": [
1167
                        {
1168
                            "id": "1",
1169
                            "frequency": "* * * * *",
1170
                            "action": "create"
1171
                        }
1172
                    ],
1173
                }
1174
            }
1175
        }
1176
1177 1
        validate_mock.return_value = True
1178 1
        mongo_controller_upsert_mock.return_value = True
1179 1
        sched_add_mock.return_value = True
1180 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1181 1
        evc_as_dict_mock.return_value = {}
1182 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1183 1
        scheduler_remove_job_mock.return_value = True
1184
1185 1
        requested_schedule_id = "1"
1186 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1187
1188 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1189
1190
        # Call URL
1191 1
        response = await self.api_client.patch(url, json=payload)
1192 1
        response_json = response.json()
1193
1194 1
        assert response.status_code == 200
1195 1
        scheduler_remove_job_mock.assert_called_once()
1196 1
        mongo_controller_upsert_mock.assert_called_once()
1197 1
        assert payload["frequency"] == response_json["frequency"]
1198 1
        assert payload["action"] == response_json["action"]
1199 1
        assert response_json["id"] is not None
1200
1201 1
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1202 1
    async def test_update_no_schedule(
1203
        self, find_evc_by_schedule_id_mock
1204
    ):
1205
        """Test update a circuit schedule."""
1206 1
        self.napp.controller.loop = asyncio.get_running_loop()
1207 1
        url = f"{self.base_endpoint}/v2/evc/schedule/1"
1208 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1209
1210 1
        find_evc_by_schedule_id_mock.return_value = None, None
1211
1212 1
        response = await self.api_client.patch(url, json=payload)
1213
        assert response.status_code == 404
1214
1215 1
    @patch("apscheduler.schedulers.background.BackgroundScheduler.remove_job")
1216 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1217 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1218 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1219 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1220 1
    async def test_delete_schedule(self, *args):
1221
        """Test create a circuit schedule."""
1222 1
        (
1223
            validate_mock,
1224
            evc_as_dict_mock,
1225
            mongo_controller_upsert_mock,
1226
            uni_from_dict_mock,
1227
            scheduler_remove_job_mock,
1228
        ) = args
1229
1230 1
        mongo_payload_1 = {
1231
            "circuits": {
1232
                "2": {
1233
                    "id": "2",
1234
                    "name": "my evc1",
1235
                    "uni_a": {
1236
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1237
                        "tag": {"tag_type": 'vlan', "value": 80},
1238
                    },
1239
                    "uni_z": {
1240
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1241
                        "tag": {"tag_type": 'vlan', "value": 1},
1242
                    },
1243
                    "circuit_scheduler": [
1244
                        {
1245
                            "id": "1",
1246
                            "frequency": "* * * * *",
1247
                            "action": "create"
1248
                        }
1249
                    ],
1250
                }
1251
            }
1252
        }
1253 1
        validate_mock.return_value = True
1254 1
        mongo_controller_upsert_mock.return_value = True
1255 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1256 1
        evc_as_dict_mock.return_value = {}
1257 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1258 1
        scheduler_remove_job_mock.return_value = True
1259
1260 1
        requested_schedule_id = "1"
1261 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1262
1263
        # Call URL
1264 1
        response = await self.api_client.delete(url)
1265
1266 1
        assert response.status_code == 200
1267 1
        scheduler_remove_job_mock.assert_called_once()
1268 1
        mongo_controller_upsert_mock.assert_called_once()
1269 1
        assert "Schedule removed" in f"{response.json()}"
1270
1271 1
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1272 1
    async def test_delete_schedule_not_found(self, mock_find_evc_by_sched):
1273
        """Test delete a circuit schedule - unexisting."""
1274 1
        mock_find_evc_by_sched.return_value = (None, False)
1275 1
        url = f'{self.base_endpoint}/v2/evc/schedule/1'
1276 1
        response = await self.api_client.delete(url)
1277
        assert response.status_code == 404
1278
1279 1
    def test_get_evcs_by_svc_level(self) -> None:
1280
        """Test get_evcs_by_svc_level."""
1281 1
        levels = [1, 2, 4, 2, 7]
1282 1
        evcs = {i: MagicMock(service_level=v, creation_time=1)
1283
                for i, v in enumerate(levels)}
1284 1
        self.napp.circuits = evcs
1285 1
        expected_levels = sorted(levels, reverse=True)
1286 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1287 1
        assert evcs_by_level
1288
1289 1
        for evc, exp_level in zip(evcs_by_level, expected_levels):
1290 1
            assert evc.service_level == exp_level
1291
1292 1
        evcs = {i: MagicMock(service_level=1, creation_time=i)
1293
                for i in reversed(range(2))}
1294 1
        self.napp.circuits = evcs
1295 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1296 1
        for i in range(2):
1297 1
            assert evcs_by_level[i].creation_time == i
1298
1299 1
        self.napp.circuits[1].is_enabled = lambda: False
1300 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1301 1
        assert len(evcs_by_level) == 1
1302
1303 1
        self.napp.circuits[1].is_enabled = lambda: False
1304 1
        evcs_by_level = self.napp.get_evcs_by_svc_level(enable_filter=False)
1305 1
        assert len(evcs_by_level) == 2
1306
1307 1
    async def test_get_circuit_not_found(self):
1308
        """Test /v2/evc/<circuit_id> 404."""
1309 1
        self.napp.mongo_controller.get_circuit.return_value = None
1310 1
        url = f'{self.base_endpoint}/v2/evc/1234'
1311 1
        response = await self.api_client.get(url)
1312
        assert response.status_code == 404
1313
1314 1
    @patch('httpx.post')
1315 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1316 1
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1317 1
    @patch('napps.kytos.mef_eline.controllers.ELineController.update_evc')
1318 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1319 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1320 1
    @patch('kytos.core.Controller.get_interface_by_id')
1321 1
    @patch('napps.kytos.mef_eline.models.path.Path.is_valid')
1322 1
    @patch('napps.kytos.mef_eline.models.evc.EVCDeploy.deploy')
1323 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1324 1
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1325 1
    async def test_update_circuit(
1326
        self,
1327
        evc_as_dict_mock,
1328
        uni_from_dict_mock,
1329
        evc_deploy,
1330
        _is_valid_mock,
1331
        interface_by_id_mock,
1332
        _mock_validate,
1333
        _mongo_controller_upsert_mock,
1334
        _mongo_controller_update_mock,
1335
        _sched_add_mock,
1336
        mock_use_uni_tags,
1337
        httpx_mock
1338
    ):
1339
        """Test update a circuit circuit."""
1340 1
        self.napp.controller.loop = asyncio.get_running_loop()
1341 1
        mock_use_uni_tags.return_value = True
1342 1
        evc_deploy.return_value = True
1343 1
        interface_by_id_mock.return_value = get_uni_mocked().interface
1344 1
        unis = [
1345
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:01"),
1346
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:02"),
1347
        ]
1348 1
        uni_from_dict_mock.side_effect = 2 * unis
1349
1350 1
        response = MagicMock()
1351 1
        response.status_code = 201
1352 1
        httpx_mock.return_value = response
1353
1354 1
        payloads = [
1355
            {
1356
                "name": "my evc1",
1357
                "uni_a": {
1358
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1359
                    "tag": {"tag_type": 'vlan', "value": 80},
1360
                },
1361
                "uni_z": {
1362
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1363
                    "tag": {"tag_type": 'vlan', "value": 1},
1364
                },
1365
                "dynamic_backup_path": True,
1366
            },
1367
            {
1368
                "primary_path": [
1369
                    {
1370
                        "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1371
                        "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1372
                    }
1373
                ]
1374
            },
1375
            {
1376
                "sb_priority": 3
1377
            },
1378
            {
1379
                # It works only with 'enabled' and not with 'enable'
1380
                "enabled": True
1381
            },
1382
            {
1383
                "sb_priority": 100
1384
            }
1385
        ]
1386
1387 1
        evc_as_dict_mock.return_value = payloads[0]
1388 1
        response = await self.api_client.post(
1389
            f"{self.base_endpoint}/v2/evc/",
1390
            json=payloads[0],
1391
        )
1392 1
        assert 201 == response.status_code
1393
1394 1
        evc_deploy.reset_mock()
1395 1
        evc_as_dict_mock.return_value = payloads[1]
1396 1
        current_data = response.json()
1397 1
        circuit_id = current_data["circuit_id"]
1398 1
        response = await self.api_client.patch(
1399
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1400
            json=payloads[1],
1401
        )
1402
        # evc_deploy.assert_called_once()
1403 1
        assert 200 == response.status_code
1404
1405 1
        evc_deploy.reset_mock()
1406 1
        evc_as_dict_mock.return_value = payloads[2]
1407 1
        response = await self.api_client.patch(
1408
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1409
            json=payloads[2],
1410
        )
1411 1
        evc_deploy.assert_not_called()
1412 1
        assert 200 == response.status_code
1413
1414 1
        evc_deploy.reset_mock()
1415 1
        evc_as_dict_mock.return_value = payloads[3]
1416 1
        response = await self.api_client.patch(
1417
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1418
            json=payloads[3],
1419
        )
1420 1
        evc_deploy.assert_called_once()
1421 1
        assert 200 == response.status_code
1422
1423 1
        evc_deploy.reset_mock()
1424 1
        response = await self.api_client.patch(
1425
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1426
            content=b'{"priority":5,}',
1427
            headers={"Content-Type": "application/json"}
1428
        )
1429
        evc_deploy.assert_not_called()
1430
        assert 400 == response.status_code
1431
1432
        response = await self.api_client.patch(
1433
            f"{self.base_endpoint}/v2/evc/1234",
1434
            json=payloads[1],
1435
        )
1436
        current_data = response.json()
1437
        expected_data = "circuit_id 1234 not found"
1438
        assert current_data["description"] == expected_data
1439
        assert 404 == response.status_code
1440
1441
        self.napp.circuits[circuit_id]._active = False
1442
        evc_deploy.reset_mock()
1443
        response = await self.api_client.patch(
1444
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1445
            json=payloads[4]
1446
        )
1447 1
        assert 200 == response.status_code
1448 1
        evc_deploy.assert_called_once()
1449
1450 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...
1451 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1452 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1453 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1454 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1455 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1456 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1457 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1458 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1459 1
    async def test_update_circuit_invalid_json(
1460
        self,
1461
        evc_as_dict_mock,
1462
        validate_mock,
1463
        mongo_controller_upsert_mock,
1464
        uni_from_dict_mock,
1465
        sched_add_mock,
1466
        evc_deploy_mock,
1467
        mock_use_uni_tags,
1468
        mock_tags_equal,
1469
        mock_check_duplicate
1470
    ):
1471
        """Test update a circuit circuit."""
1472 1
        self.napp.controller.loop = asyncio.get_running_loop()
1473 1
        validate_mock.return_value = True
1474 1
        mongo_controller_upsert_mock.return_value = True
1475 1
        sched_add_mock.return_value = True
1476 1
        evc_deploy_mock.return_value = True
1477 1
        mock_use_uni_tags.return_value = True
1478 1
        mock_tags_equal.return_value = True
1479 1
        mock_check_duplicate.return_value = True
1480 1
        uni1 = create_autospec(UNI)
1481 1
        uni2 = create_autospec(UNI)
1482 1
        uni1.interface = create_autospec(Interface)
1483 1
        uni2.interface = create_autospec(Interface)
1484 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1485 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1486 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1487
1488 1
        payload1 = {
1489
            "name": "my evc1",
1490
            "uni_a": {
1491
                "interface_id": "00:00:00:00:00:00:00:01:1",
1492
                "tag": {"tag_type": 'vlan', "value": 80},
1493
            },
1494
            "uni_z": {
1495
                "interface_id": "00:00:00:00:00:00:00:02:2",
1496
                "tag": {"tag_type": 'vlan', "value": 1},
1497
            },
1498
            "dynamic_backup_path": True,
1499
        }
1500
1501 1
        payload2 = {
1502
            "dynamic_backup_path": False,
1503
        }
1504
1505 1
        evc_as_dict_mock.return_value = payload1
1506 1
        response = await self.api_client.post(
1507
            f"{self.base_endpoint}/v2/evc/",
1508
            json=payload1
1509
        )
1510 1
        assert 201 == response.status_code
1511
1512 1
        evc_as_dict_mock.return_value = payload2
1513 1
        current_data = response.json()
1514 1
        circuit_id = current_data["circuit_id"]
1515 1
        response = await self.api_client.patch(
1516
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1517
            json=payload2
1518
        )
1519
        current_data = response.json()
1520
        assert 400 == response.status_code
1521
        assert "must have a primary path or" in current_data["description"]
1522
1523 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
1524 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1525 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1526 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1527 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1528 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1529 1
    @patch("napps.kytos.mef_eline.main.Main._link_from_dict")
1530 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1531 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1532 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1533 1
    @patch("napps.kytos.mef_eline.models.path.Path.is_valid")
1534 1
    async def test_update_circuit_invalid_path(
1535
        self,
1536
        is_valid_mock,
1537
        evc_as_dict_mock,
1538
        validate_mock,
1539
        mongo_controller_upsert_mock,
1540
        link_from_dict_mock,
1541
        uni_from_dict_mock,
1542
        sched_add_mock,
1543
        evc_deploy_mock,
1544
        mock_use_uni_tags,
1545
        mock_tags_equal,
1546
        mock_check_duplicate
1547
    ):
1548
        """Test update a circuit circuit."""
1549 1
        self.napp.controller.loop = asyncio.get_running_loop()
1550 1
        is_valid_mock.side_effect = InvalidPath("error")
1551 1
        validate_mock.return_value = True
1552 1
        mongo_controller_upsert_mock.return_value = True
1553 1
        sched_add_mock.return_value = True
1554 1
        evc_deploy_mock.return_value = True
1555 1
        mock_use_uni_tags.return_value = True
1556 1
        link_from_dict_mock.return_value = 1
1557 1
        mock_tags_equal.return_value = True
1558 1
        mock_check_duplicate.return_value = True
1559 1
        uni1 = create_autospec(UNI)
1560 1
        uni2 = create_autospec(UNI)
1561 1
        uni1.interface = create_autospec(Interface)
1562 1
        uni2.interface = create_autospec(Interface)
1563 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1564 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1565 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1566
1567 1
        payload1 = {
1568
            "name": "my evc1",
1569
            "uni_a": {
1570
                "interface_id": "00:00:00:00:00:00:00:01:1",
1571
                "tag": {"tag_type": 'vlan', "value": 80},
1572
            },
1573
            "uni_z": {
1574
                "interface_id": "00:00:00:00:00:00:00:02:2",
1575
                "tag": {"tag_type": 'vlan', "value": 1},
1576
            },
1577
            "dynamic_backup_path": True,
1578
        }
1579
1580 1
        payload2 = {
1581
            "primary_path": [
1582
                {
1583
                    "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1584
                    "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1585
                }
1586
            ]
1587
        }
1588
1589 1
        evc_as_dict_mock.return_value = payload1
1590 1
        response = await self.api_client.post(
1591
            f"{self.base_endpoint}/v2/evc/",
1592
            json=payload1,
1593
        )
1594 1
        assert 201 == response.status_code
1595
1596 1
        evc_as_dict_mock.return_value = payload2
1597 1
        current_data = response.json()
1598 1
        circuit_id = current_data["circuit_id"]
1599 1
        response = await self.api_client.patch(
1600
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1601
            json=payload2,
1602
        )
1603
        current_data = response.json()
1604
        expected_data = "primary_path is not a valid path: error"
1605
        assert 400 == response.status_code
1606
        assert current_data["description"] == expected_data
1607
1608 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._get_unis_use_tags")
1609 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1610 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1611 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1612 1
    @patch('napps.kytos.mef_eline.models.evc.EVCDeploy.deploy')
1613 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1614 1
    async def test_update_disabled_intra_switch(
1615
        self,
1616
        uni_from_dict_mock,
1617
        evc_deploy,
1618
        _mock_validate,
1619
        _mongo_controller_upsert_mock,
1620
        mock_use_uni_tags,
1621
        mock_get_unis
1622
    ):
1623
        """Test update a circuit that result in an intra-switch EVC
1624
        with disabled switches or interfaces"""
1625 1
        evc_deploy.return_value = True
1626 1
        _mock_validate.return_value = True
1627 1
        _mongo_controller_upsert_mock.return_value = True
1628 1
        mock_use_uni_tags.return_value = True
1629 1
        self.napp.controller.loop = asyncio.get_running_loop()
1630
        # Interfaces from get_uni_mocked() are disabled
1631 1
        uni_a = get_uni_mocked(
1632
            switch_dpid="00:00:00:00:00:00:00:01",
1633
            switch_id="00:00:00:00:00:00:00:01"
1634
        )
1635 1
        uni_z = get_uni_mocked(
1636
            switch_dpid="00:00:00:00:00:00:00:02",
1637
            switch_id="00:00:00:00:00:00:00:02"
1638
        )
1639 1
        unis = [uni_a, uni_z]
1640 1
        uni_from_dict_mock.side_effect = 2 * unis
1641
1642 1
        evc_payload = {
1643
            "name": "Intra-EVC",
1644
            "dynamic_backup_path": True,
1645
            "uni_a": {
1646
                "tag": {"value": 101, "tag_type": 'vlan'},
1647
                "interface_id": "00:00:00:00:00:00:00:02:2"
1648
            },
1649
            "uni_z": {
1650
                "tag": {"value": 101, "tag_type": 'vlan'},
1651
                "interface_id": "00:00:00:00:00:00:00:01:1"
1652
            }
1653
        }
1654
1655
        # With this update the EVC will be intra-switch
1656 1
        update_payload = {
1657
            "uni_z": {
1658
                "tag": {"value": 101, "tag_type": 'vlan'},
1659
                "interface_id": "00:00:00:00:00:00:00:02:1"
1660
            }
1661
        }
1662
        # Same mocks = intra-switch
1663 1
        mock_get_unis.return_value = [uni_z, uni_z]
1664 1
        response = await self.api_client.post(
1665
            f"{self.base_endpoint}/v2/evc/",
1666
            json=evc_payload,
1667
        )
1668 1
        assert 201 == response.status_code
1669 1
        current_data = response.json()
1670 1
        circuit_id = current_data["circuit_id"]
1671
1672 1
        response = await self.api_client.patch(
1673
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1674
            json=update_payload,
1675
        )
1676
        assert 409 == response.status_code
1677
        description = "00:00:00:00:00:00:00:02:1 is disabled"
1678
        assert description in response.json()["description"]
1679
1680 1
    def test_link_from_dict_non_existent_intf(self):
1681
        """Test _link_from_dict non existent intf."""
1682 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1683 1
        link_dict = {
1684
            "endpoint_a": {"id": "a"},
1685
            "endpoint_b": {"id": "b"}
1686
        }
1687 1
        with pytest.raises(ValueError):
1688 1
            self.napp._link_from_dict(link_dict, "current_path")
1689
1690 1
    def test_link_from_dict_vlan_metadata(self):
1691
        """Test that link_from_dict only accepts vlans for current_path
1692
         and failover_path."""
1693 1
        intf = MagicMock(id="01:1")
1694 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=intf)
1695 1
        link_dict = {
1696
            'id': 'mock_link',
1697
            'endpoint_a': {'id': '00:00:00:00:00:00:00:01:4'},
1698
            'endpoint_b': {'id': '00:00:00:00:00:00:00:05:2'},
1699
            'metadata': {'s_vlan': {'tag_type': 'vlan', 'value': 1}}
1700
        }
1701 1
        link = self.napp._link_from_dict(link_dict, "current_path")
1702 1
        assert link.metadata.get('s_vlan', None)
1703
1704 1
        link = self.napp._link_from_dict(link_dict, "failover_path")
1705 1
        assert link.metadata.get('s_vlan', None)
1706
1707 1
        link = self.napp._link_from_dict(link_dict, "primary_path")
1708 1
        assert link.metadata.get('s_vlan', None) is None
1709
1710 1
    def test_uni_from_dict_non_existent_intf(self):
1711
        """Test _link_from_dict non existent intf."""
1712 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1713 1
        uni_dict = {
1714
            "interface_id": "aaa",
1715
        }
1716 1
        with pytest.raises(ValueError):
1717 1
            self.napp._uni_from_dict(uni_dict)
1718
1719 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...
1720 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1721 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1722 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1723 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1724 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1725 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1726 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1727 1
    async def test_update_evc_no_json_mime(
1728
        self,
1729
        mongo_controller_upsert_mock,
1730
        validate_mock,
1731
        uni_from_dict_mock,
1732
        sched_add_mock,
1733
        evc_deploy_mock,
1734
        mock_use_uni_tags,
1735
        mock_tags_equal,
1736
        mock_check_duplicate
1737
    ):
1738
        """Test update a circuit with wrong mimetype."""
1739 1
        self.napp.controller.loop = asyncio.get_running_loop()
1740 1
        validate_mock.return_value = True
1741 1
        sched_add_mock.return_value = True
1742 1
        evc_deploy_mock.return_value = True
1743 1
        mock_use_uni_tags.return_value = True
1744 1
        mock_tags_equal.return_value = True
1745 1
        mock_check_duplicate.return_value = True
1746 1
        uni1 = create_autospec(UNI)
1747 1
        uni2 = create_autospec(UNI)
1748 1
        uni1.interface = create_autospec(Interface)
1749 1
        uni2.interface = create_autospec(Interface)
1750 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1751 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1752 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1753 1
        mongo_controller_upsert_mock.return_value = True
1754
1755 1
        payload1 = {
1756
            "name": "my evc1",
1757
            "uni_a": {
1758
                "interface_id": "00:00:00:00:00:00:00:01:1",
1759
                "tag": {"tag_type": 'vlan', "value": 80},
1760
            },
1761
            "uni_z": {
1762
                "interface_id": "00:00:00:00:00:00:00:02:2",
1763
                "tag": {"tag_type": 'vlan', "value": 1},
1764
            },
1765
            "dynamic_backup_path": True,
1766
        }
1767
1768 1
        payload2 = {"dynamic_backup_path": False}
1769
1770 1
        response = await self.api_client.post(
1771
            f"{self.base_endpoint}/v2/evc/",
1772
            json=payload1,
1773
        )
1774 1
        assert 201 == response.status_code
1775
1776 1
        current_data = response.json()
1777 1
        circuit_id = current_data["circuit_id"]
1778 1
        response = await self.api_client.patch(
1779
            f"{self.base_endpoint}/v2/evc/{circuit_id}", data=payload2
1780
        )
1781
        current_data = response.json()
1782
        assert 415 == response.status_code
1783
        assert "application/json" in current_data["description"]
1784
1785 1
    async def test_delete_no_evc(self):
1786
        """Test delete when EVC does not exist."""
1787 1
        url = f"{self.base_endpoint}/v2/evc/123"
1788 1
        response = await self.api_client.delete(url)
1789
        current_data = response.json()
1790
        expected_data = "circuit_id 123 not found"
1791
        assert current_data["description"] == expected_data
1792
        assert 404 == response.status_code
1793
1794 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
1795 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1796 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_uni_tags")
1797 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1798 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_current_flows")
1799 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1800 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1801 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1802 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1803 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1804 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1805 1
    async def test_delete_archived_evc(
1806
        self,
1807
        evc_as_dict_mock,
1808
        validate_mock,
1809
        mongo_controller_upsert_mock,
1810
        uni_from_dict_mock,
1811
        sched_add_mock,
1812
        evc_deploy_mock,
1813
        remove_current_flows_mock,
1814
        mock_use_uni,
1815
        mock_remove_tags,
1816
        mock_tags_equal,
1817
        mock_check_duplicate
1818
    ):
1819
        """Try to delete an archived EVC"""
1820 1
        self.napp.controller.loop = asyncio.get_running_loop()
1821 1
        validate_mock.return_value = True
1822 1
        mongo_controller_upsert_mock.return_value = True
1823 1
        sched_add_mock.return_value = True
1824 1
        evc_deploy_mock.return_value = True
1825 1
        mock_use_uni.return_value = True
1826 1
        mock_tags_equal.return_value = True
1827 1
        mock_check_duplicate.return_value = True
1828 1
        uni1 = create_autospec(UNI)
1829 1
        uni2 = create_autospec(UNI)
1830 1
        uni1.interface = create_autospec(Interface)
1831 1
        uni2.interface = create_autospec(Interface)
1832 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1833 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1834 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1835
1836 1
        payload1 = {
1837
            "name": "my evc1",
1838
            "uni_a": {
1839
                "interface_id": "00:00:00:00:00:00:00:01:1",
1840
                "tag": {"tag_type": 'vlan', "value": 80},
1841
            },
1842
            "uni_z": {
1843
                "interface_id": "00:00:00:00:00:00:00:02:2",
1844
                "tag": {"tag_type": 'vlan', "value": 1},
1845
            },
1846
            "dynamic_backup_path": True,
1847
        }
1848
1849 1
        evc_as_dict_mock.return_value = payload1
1850 1
        response = await self.api_client.post(
1851
            f"{self.base_endpoint}/v2/evc/",
1852
            json=payload1
1853
        )
1854 1
        assert 201 == response.status_code
1855 1
        assert len(self.napp.circuits) == 1
1856 1
        current_data = response.json()
1857 1
        circuit_id = current_data["circuit_id"]
1858 1
        self.napp.circuits[circuit_id].archive()
1859
1860 1
        response = await self.api_client.delete(
1861
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1862
        )
1863 1
        assert 200 == response.status_code
1864 1
        assert mock_remove_tags.call_count == 0
1865 1
        assert remove_current_flows_mock.call_count == 0
1866 1
        assert len(self.napp.circuits) == 0
1867
1868 1
        response = await self.api_client.delete(
1869
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1870
        )
1871
        current_data = response.json()
1872
        expected_data = f"circuit_id {circuit_id} not found"
1873
        assert current_data["description"] == expected_data
1874
        assert 404 == response.status_code
1875
        assert len(self.napp.circuits) == 0
1876
1877 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1878 1
    async def test_delete_circuit(self, emit_event_mock):
1879
        """Test delete_circuit"""
1880 1
        evc = MagicMock()
1881 1
        evc.archived = False
1882 1
        circuit_id = '1'
1883 1
        self.napp.circuits[circuit_id] = evc
1884 1
        response = await self.api_client.delete(
1885
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1886
        )
1887 1
        assert 200 == response.status_code
1888 1
        assert evc.deactivate.call_count == 1
1889 1
        assert evc.disable.call_count == 1
1890 1
        evc.remove_current_flows.assert_called_once_with(
1891
            sync=False
1892
        )
1893 1
        evc.remove_failover_flows.assert_called_once_with(
1894
            sync=False
1895
        )
1896 1
        assert evc.archive.call_count == 1
1897 1
        assert evc.remove_uni_tags.call_count == 1
1898 1
        assert evc.sync.call_count == 1
1899 1
        assert not self.napp.circuits
1900 1
        assert emit_event_mock.call_count == 1
1901
1902 1
    def test_handle_link_up(self):
1903
        """Test handle_link_up method."""
1904 1
        evc_mock = create_autospec(EVC)
1905 1
        evc_mock.service_level, evc_mock.creation_time = 0, 1
1906 1
        evc_mock.is_enabled = MagicMock(side_effect=[
1907
            True, False, True, True, True
1908
        ])
1909 1
        evc_mock.lock = MagicMock()
1910 1
        evc_mock.archived = False
1911 1
        evcs = [evc_mock, evc_mock, evc_mock]
1912 1
        event = KytosEvent(name="test", content={"link": "abc"})
1913 1
        self.napp.circuits = dict(zip(["1", "2", "3"], evcs))
1914 1
        self.napp.handle_link_up(event)
1915 1
        assert evc_mock.handle_link_up.call_count == 2
1916 1
        evc_mock.handle_link_up.assert_called_with("abc")
1917
1918 1
    @pytest.mark.xfail(
1919
        reason="Hasn't been updated for the latest changes to link down"
1920
    )
1921 1
    @patch("time.sleep", return_value=None)
1922 1
    @patch("napps.kytos.mef_eline.utils.emit_event")
1923 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1924 1
    def test_handle_link_down(
1925
        self, emit_main_mock, emit_utils_mock, _
1926
    ):
1927
        """Test handle_link_down method."""
1928 1
        uni = create_autospec(UNI)
1929 1
        evc1 = MagicMock(id="1", service_level=0, creation_time=1,
1930
                         metadata="mock", _active="true", _enabled="true",
1931
                         uni_a=uni, uni_z=uni)
1932 1
        evc1.name = "name"
1933 1
        evc1.is_affected_by_link.return_value = True
1934 1
        evc1.handle_link_down.return_value = True
1935 1
        evc1.failover_path = None
1936 1
        evc2 = MagicMock(id="2", service_level=6, creation_time=1)
1937 1
        evc2.is_affected_by_link.return_value = False
1938 1
        evc2.is_failover_path_affected_by_link.return_value = True
1939 1
        evc2.as_dict.return_value = {"id": "2"}
1940 1
        evc3 = MagicMock(id="3", service_level=5, creation_time=1,
1941
                         metadata="mock", _active="true", _enabled="true",
1942
                         uni_a=uni, uni_z=uni)
1943 1
        evc3.name = "name"
1944 1
        evc3.is_affected_by_link.return_value = True
1945 1
        evc3.handle_link_down.return_value = True
1946 1
        evc3.failover_path = None
1947 1
        evc4 = MagicMock(id="4", service_level=4, creation_time=1,
1948
                         metadata="mock", _active="true", _enabled="true",
1949
                         uni_a=uni, uni_z=uni)
1950 1
        evc4.name = "name"
1951 1
        evc4.is_affected_by_link.return_value = True
1952 1
        evc4.is_failover_path_affected_by_link.return_value = False
1953 1
        evc4.failover_path = ["2"]
1954 1
        evc4.get_failover_flows.return_value = {
1955
            "2": ["flow1", "flow2"],
1956
            "3": ["flow3", "flow4", "flow5", "flow6"],
1957
        }
1958 1
        evc4.as_dict.return_value = {"id": "4"}
1959 1
        evc5 = MagicMock(id="5", service_level=7, creation_time=1)
1960 1
        evc5.is_affected_by_link.return_value = True
1961 1
        evc5.is_failover_path_affected_by_link.return_value = False
1962 1
        evc5.failover_path = ["3"]
1963 1
        evc5.get_failover_flows.return_value = {
1964
            "4": ["flow7", "flow8"],
1965
            "5": ["flow9", "flow10"],
1966
        }
1967 1
        evc5.as_dict.return_value = {"id": "5"}
1968 1
        evc6 = MagicMock(id="6", service_level=8, creation_time=1,
1969
                         metadata="mock", _active="true", _enabled="true",
1970
                         uni_a=uni, uni_z=uni)
1971 1
        evc6.name = "name"
1972 1
        evc6.is_affected_by_link.return_value = True
1973 1
        evc6.is_failover_path_affected_by_link.return_value = False
1974 1
        evc6.failover_path = ["3"]
1975 1
        evc6.get_failover_flows.side_effect = AttributeError("err")
1976 1
        link = MagicMock(id="123")
1977 1
        event = KytosEvent(name="test", content={"link": link})
1978 1
        self.napp.circuits = {"1": evc1, "2": evc2, "3": evc3, "4": evc4,
1979
                              "5": evc5, "6": evc6}
1980 1
        self.napp.handle_link_down(event)
1981
1982 1
        assert evc5.service_level > evc4.service_level
1983
        # evc5 batched flows should be sent first
1984 1
        emit_utils_mock.assert_has_calls([
1985
            call(
1986
                self.napp.controller,
1987
                context="kytos.flow_manager",
1988
                name="flows.install",
1989
                content={
1990
                    "dpid": "4",
1991
                    "flow_dict": {"flows": ["flow7", "flow8"]},
1992
                    'force': True,
1993
                }
1994
            ),
1995
            call(
1996
                self.napp.controller,
1997
                context="kytos.flow_manager",
1998
                name="flows.install",
1999
                content={
2000
                    "dpid": "5",
2001
                    "flow_dict": {"flows": ["flow9", "flow10"]},
2002
                    'force': True,
2003
                }
2004
            ),
2005
            call(
2006
                self.napp.controller,
2007
                context="kytos.flow_manager",
2008
                name="flows.install",
2009
                content={
2010
                    "dpid": "2",
2011
                    "flow_dict": {"flows": ["flow1", "flow2"]},
2012
                    'force': True,
2013
                }
2014
            ),
2015
            call(
2016
                self.napp.controller,
2017
                context="kytos.flow_manager",
2018
                name="flows.install",
2019
                content={
2020
                    "dpid": "3",
2021
                    "flow_dict": {
2022
                        "flows": ["flow3", "flow4", "flow5", "flow6"]
2023
                    },
2024
                    'force': True,
2025
                }
2026
            )
2027
        ])
2028
        event_name = "evc_affected_by_link_down"
2029
        assert evc3.service_level > evc1.service_level
2030
        # evc3 should be handled before evc1
2031
        emit_main_mock.assert_has_calls([
2032
            call(self.napp.controller, event_name, content={
2033
                "link": link,
2034
                "id": "6",
2035
                "evc_id": "6",
2036
                "name": "name",
2037
                "metadata": "mock",
2038
                "active": "true",
2039
                "enabled": "true",
2040
                "uni_a": uni.as_dict(),
2041
                "uni_z": uni.as_dict(),
2042
            }),
2043
            call(self.napp.controller, event_name, content={
2044
                "link": link,
2045
                "evc_id": "3",
2046
                "id": "3",
2047
                "name": "name",
2048
                "metadata": "mock",
2049
                "active": "true",
2050
                "enabled": "true",
2051
                "uni_a": uni.as_dict(),
2052
                "uni_z": uni.as_dict(),
2053
            }),
2054
            call(self.napp.controller, event_name, content={
2055
                "link": link,
2056
                "evc_id": "1",
2057
                "id": "1",
2058
                "name": "name",
2059
                "metadata": "mock",
2060
                "active": "true",
2061
                "enabled": "true",
2062
                "uni_a": uni.as_dict(),
2063
                "uni_z": uni.as_dict(),
2064
            }),
2065
        ])
2066
        self.napp.mongo_controller.update_evcs.assert_called_with(
2067
            [{"id": "5"}, {"id": "4"}, {"id": "2"}]
2068
        )
2069
        event_name = "failover_link_down"
2070
        assert emit_main_mock.call_args_list[0][0][1] == event_name
2071
2072 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2073 1
    def test_handle_evc_affected_by_link_down(self, emit_event_mock):
2074
        """Test handle_evc_affected_by_link_down method."""
2075 1
        uni = create_autospec(UNI)
2076 1
        evc1 = MagicMock(
2077
            id="1",
2078
            metadata="data_mocked",
2079
            _active="true",
2080
            _enabled="false",
2081
            uni_a=uni,
2082
            uni_z=uni,
2083
        )
2084 1
        evc1.name = "name_mocked"
2085 1
        evc1.handle_link_down.return_value = True
2086 1
        evc2 = MagicMock(
2087
            id="2",
2088
            metadata="mocked_data",
2089
            _active="false",
2090
            _enabled="true",
2091
            uni_a=uni,
2092
            uni_z=uni,
2093
        )
2094 1
        evc2.name = "mocked_name"
2095 1
        evc2.handle_link_down.return_value = False
2096 1
        self.napp.circuits = {"1": evc1, "2": evc2}
2097
2098 1
        event = KytosEvent(name="e1", content={
2099
            "evc_id": "3",
2100
            "link": MagicMock(),
2101
        })
2102 1
        self.napp.handle_evc_affected_by_link_down(event)
2103 1
        emit_event_mock.assert_not_called()
2104 1
        event.content["evc_id"] = "1"
2105 1
        self.napp.handle_evc_affected_by_link_down(event)
2106 1
        emit_event_mock.assert_called_with(
2107
            self.napp.controller, "redeployed_link_down", content={
2108
                "id": "1",
2109
                "evc_id": "1",
2110
                "name": "name_mocked",
2111
                "metadata": "data_mocked",
2112
                "active": "true",
2113
                "enabled": "false",
2114
                "uni_a": uni.as_dict(),
2115
                "uni_z": uni.as_dict(),
2116
            }
2117
        )
2118
2119 1
        event.content["evc_id"] = "2"
2120 1
        self.napp.handle_evc_affected_by_link_down(event)
2121 1
        emit_event_mock.assert_called_with(
2122
            self.napp.controller, "error_redeploy_link_down", content={
2123
                "evc_id": "2",
2124
                "id": "2",
2125
                "name": "mocked_name",
2126
                "metadata": "mocked_data",
2127
                "active": "false",
2128
                "enabled": "true",
2129
                "uni_a": uni.as_dict(),
2130
                "uni_z": uni.as_dict(),
2131
            }
2132
        )
2133
2134 1
    def test_cleanup_evcs_old_path(self, monkeypatch):
2135
        """Test handle_cleanup_evcs_old_path method."""
2136 1
        current_path, map_evc_content, emit_event = [
2137
            MagicMock(), MagicMock(), MagicMock()
2138
        ]
2139 1
        send_flows, merge_flows, create_flows = [
2140
            MagicMock(), MagicMock(), MagicMock()
2141
        ]
2142 1
        monkeypatch.setattr(
2143
            "napps.kytos.mef_eline.main.map_evc_event_content",
2144
            map_evc_content
2145
        )
2146 1
        monkeypatch.setattr(
2147
            "napps.kytos.mef_eline.main.emit_event",
2148
            emit_event
2149
        )
2150 1
        monkeypatch.setattr(
2151
            "napps.kytos.mef_eline.main.send_flow_mods_event",
2152
            send_flows
2153
        )
2154 1
        monkeypatch.setattr(
2155
            "napps.kytos.mef_eline.main.merge_flow_dicts",
2156
            merge_flows
2157
        )
2158 1
        monkeypatch.setattr(
2159
            "napps.kytos.mef_eline.main.prepare_delete_flow",
2160
            create_flows
2161
        )
2162 1
        merge_flows.return_value = ['1', '2']
2163 1
        evc1 = create_autospec(EVC, id="1", old_path=["1"],
2164
                               current_path=current_path, lock=MagicMock())
2165 1
        evc2 = create_autospec(EVC, id="2", old_path=["2"],
2166
                               current_path=current_path, lock=MagicMock())
2167 1
        evc3 = create_autospec(EVC, id="3", old_path=[],
2168
                               current_path=[], lock=MagicMock())
2169
2170 1
        event = KytosEvent(name="e1", content={"evcs": [evc1, evc2, evc3]})
2171 1
        assert evc1.old_path
2172 1
        assert evc2.old_path
2173 1
        self.napp.handle_cleanup_evcs_old_path(event)
2174 1
        evc1._prepare_nni_flows.assert_called_with(["1"])
2175 1
        evc1._prepare_uni_flows.assert_called_with(["1"], skip_in=True)
2176 1
        evc2._prepare_nni_flows.assert_called_with(["2"])
2177 1
        evc2._prepare_uni_flows.assert_called_with(["2"], skip_in=True)
2178 1
        evc3._prepare_nni_flows.assert_not_called()
2179 1
        evc3._prepare_uni_flows.assert_not_called()
2180 1
        assert create_flows.call_count == 4
2181 1
        assert emit_event.call_count == 1
2182 1
        assert emit_event.call_args[0][1] == "failover_old_path"
2183 1
        assert map_evc_content.call_args[1]['removed_flows'] == ['1', '2']
2184 1
        assert len(emit_event.call_args[1]["content"]) == 2
2185 1
        assert send_flows.call_count == 1
2186 1
        assert send_flows.call_args[0][1] == ['1', '2']
2187 1
        assert send_flows.call_args[0][2] == 'delete'
2188 1
        assert merge_flows.call_count == 4
2189 1
        assert not evc1.old_path
2190 1
        assert not evc2.old_path
2191
2192 1
    async def test_add_metadata(self):
2193
        """Test method to add metadata"""
2194 1
        self.napp.controller.loop = asyncio.get_running_loop()
2195 1
        evc_mock = create_autospec(EVC)
2196 1
        evc_mock.metadata = {}
2197 1
        evc_mock.id = 1234
2198 1
        self.napp.circuits = {"1234": evc_mock}
2199
2200 1
        payload = {"metadata1": 1, "metadata2": 2}
2201 1
        response = await self.api_client.post(
2202
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2203
            json=payload
2204
        )
2205
2206 1
        assert response.status_code == 201
2207 1
        evc_mock.extend_metadata.assert_called_with(payload)
2208
2209 1
    async def test_add_metadata_malformed_json(self):
2210
        """Test method to add metadata with a malformed json"""
2211 1
        self.napp.controller.loop = asyncio.get_running_loop()
2212 1
        payload = b'{"metadata1": 1, "metadata2": 2,}'
2213 1
        response = await self.api_client.post(
2214
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2215
            content=payload,
2216
            headers={"Content-Type": "application/json"}
2217
        )
2218
2219
        assert response.status_code == 400
2220
        assert "body contains invalid API" in response.json()["description"]
2221
2222 1
    async def test_add_metadata_no_body(self):
2223
        """Test method to add metadata with no body"""
2224 1
        self.napp.controller.loop = asyncio.get_running_loop()
2225 1
        response = await self.api_client.post(
2226
            f"{self.base_endpoint}/v2/evc/1234/metadata"
2227
        )
2228
        assert response.status_code == 400
2229
        assert response.json()["description"] == \
2230
            "Missing required request body"
2231
2232 1
    async def test_add_metadata_no_evc(self):
2233
        """Test method to add metadata with no evc"""
2234 1
        self.napp.controller.loop = asyncio.get_running_loop()
2235 1
        payload = {"metadata1": 1, "metadata2": 2}
2236 1
        response = await self.api_client.post(
2237
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2238
            json=payload,
2239
        )
2240
        assert response.status_code == 404
2241
        assert response.json()["description"] == \
2242
            "circuit_id 1234 not found."
2243
2244 1
    async def test_add_metadata_wrong_content_type(self):
2245
        """Test method to add metadata with wrong content type"""
2246 1
        self.napp.controller.loop = asyncio.get_running_loop()
2247 1
        payload = {"metadata1": 1, "metadata2": 2}
2248 1
        response = await self.api_client.post(
2249
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2250
            data=payload,
2251
            headers={"Content-Type": "application/xml"}
2252
        )
2253
        assert response.status_code == 415
2254
        assert "application/xml" in response.json()["description"]
2255
2256 1
    async def test_get_metadata(self):
2257
        """Test method to get metadata"""
2258 1
        evc_mock = create_autospec(EVC)
2259 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2260 1
        evc_mock.id = 1234
2261 1
        self.napp.circuits = {"1234": evc_mock}
2262
2263 1
        response = await self.api_client.get(
2264
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2265
        )
2266 1
        assert response.status_code == 200
2267 1
        assert response.json() == {"metadata": evc_mock.metadata}
2268
2269 1
    async def test_delete_metadata(self):
2270
        """Test method to delete metadata"""
2271 1
        evc_mock = create_autospec(EVC)
2272 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2273 1
        evc_mock.id = 1234
2274 1
        self.napp.circuits = {"1234": evc_mock}
2275
2276 1
        response = await self.api_client.delete(
2277
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2278
        )
2279 1
        assert response.status_code == 200
2280
2281 1
    async def test_delete_metadata_no_evc(self):
2282
        """Test method to delete metadata with no evc"""
2283 1
        response = await self.api_client.delete(
2284
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2285
        )
2286
        assert response.status_code == 404
2287
        assert response.json()["description"] == \
2288
            "circuit_id 1234 not found."
2289
2290 1
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
2291 1
    def test_load_all_evcs(self, load_evc_mock):
2292
        """Test load_evcs method"""
2293 1
        mock_circuits = {
2294
            'circuits': {
2295
                1: 'circuit_1',
2296
                2: 'circuit_2',
2297
                3: 'circuit_3',
2298
                4: 'circuit_4'
2299
            }
2300
        }
2301 1
        self.napp.mongo_controller.get_circuits.return_value = mock_circuits
2302 1
        self.napp.circuits = {2: 'circuit_2', 3: 'circuit_3'}
2303 1
        self.napp.load_all_evcs()
2304 1
        load_evc_mock.assert_has_calls([call('circuit_1'), call('circuit_4')])
2305 1
        assert self.napp.controller.buffers.app.put.call_count > 1
2306 1
        call_args = self.napp.controller.buffers.app.put.call_args[0]
2307 1
        assert call_args[0].name == "kytos/mef_eline.evcs_loaded"
2308 1
        assert dict(call_args[0].content) == mock_circuits["circuits"]
2309 1
        timeout_d = {"timeout": 1}
2310 1
        assert self.napp.controller.buffers.app.put.call_args[1] == timeout_d
2311
2312 1
    @patch('napps.kytos.mef_eline.main.Main._evc_from_dict')
2313 1
    def test_load_evc(self, evc_from_dict_mock):
2314
        """Test _load_evc method"""
2315
        # pylint: disable=protected-access
2316
        # case 1: early return with ValueError exception
2317 1
        evc_from_dict_mock.side_effect = ValueError("err")
2318 1
        evc_dict = MagicMock()
2319 1
        assert not self.napp._load_evc(evc_dict)
2320
2321
        # case 2: early return with KytosTagError exception
2322 1
        evc_from_dict_mock.side_effect = KytosTagError("")
2323 1
        assert not self.napp._load_evc(evc_dict)
2324
2325
        # case 3: archived evc
2326 1
        evc = MagicMock()
2327 1
        evc.archived = True
2328 1
        evc_from_dict_mock.side_effect = None
2329 1
        evc_from_dict_mock.return_value = evc
2330 1
        assert not self.napp._load_evc(evc_dict)
2331
2332
        # case 4: success creating
2333 1
        evc.archived = False
2334 1
        evc.id = 1
2335 1
        self.napp.sched = MagicMock()
2336
2337 1
        result = self.napp._load_evc(evc_dict)
2338 1
        assert result == evc
2339 1
        self.napp.sched.add.assert_called_with(evc)
2340 1
        assert self.napp.circuits[1] == evc
2341
2342 1
    def test_handle_flow_mod_error(self):
2343
        """Test handle_flow_mod_error method"""
2344 1
        flow = MagicMock()
2345 1
        flow.cookie = 0xaa00000000000011
2346 1
        event = MagicMock()
2347 1
        event.content = {'flow': flow, 'error_command': 'add'}
2348 1
        evc = create_autospec(EVC)
2349 1
        evc.remove_current_flows = MagicMock()
2350 1
        evc.lock = MagicMock()
2351 1
        self.napp.circuits = {"00000000000011": evc}
2352 1
        self.napp.handle_flow_mod_error(event)
2353 1
        evc.remove_current_flows.assert_called_once()
2354
2355 1
    @patch("kytos.core.Controller.get_interface_by_id")
2356 1
    def test_uni_from_dict(self, _get_interface_by_id_mock):
2357
        """Test _uni_from_dict method."""
2358
        # pylint: disable=protected-access
2359
        # case1: early return on empty dict
2360 1
        assert not self.napp._uni_from_dict(None)
2361
2362
        # case2: invalid interface raises ValueError
2363 1
        _get_interface_by_id_mock.return_value = None
2364 1
        uni_dict = {
2365
            "interface_id": "00:01:1",
2366
            "tag": {"tag_type": 'vlan', "value": 81},
2367
        }
2368 1
        with pytest.raises(ValueError):
2369 1
            self.napp._uni_from_dict(uni_dict)
2370
2371
        # case3: success creation
2372 1
        uni_mock = get_uni_mocked(switch_id="00:01")
2373 1
        _get_interface_by_id_mock.return_value = uni_mock.interface
2374 1
        uni = self.napp._uni_from_dict(uni_dict)
2375 1
        assert uni == uni_mock
2376
2377
        # case4: success creation of tag list
2378 1
        uni_dict["tag"]["value"] = [[1, 10]]
2379 1
        uni = self.napp._uni_from_dict(uni_dict)
2380 1
        assert isinstance(uni.user_tag, TAGRange)
2381
2382
        # case5: success creation without tag
2383 1
        uni_mock.user_tag = None
2384 1
        del uni_dict["tag"]
2385 1
        uni = self.napp._uni_from_dict(uni_dict)
2386 1
        assert uni == uni_mock
2387
2388 1
    def test_handle_flow_delete(self):
2389
        """Test handle_flow_delete method"""
2390 1
        flow = MagicMock()
2391 1
        flow.cookie = 0xaa00000000000011
2392 1
        event = MagicMock()
2393 1
        event.content = {'flow': flow}
2394 1
        evc = create_autospec(EVC)
2395 1
        evc.set_flow_removed_at = MagicMock()
2396 1
        self.napp.circuits = {"00000000000011": evc}
2397 1
        self.napp.handle_flow_delete(event)
2398 1
        evc.set_flow_removed_at.assert_called_once()
2399
2400 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...
2401
        """Test add_bulk_metadata method"""
2402 1
        self.napp.controller.loop = asyncio.get_running_loop()
2403 1
        evc_mock = create_autospec(EVC)
2404 1
        evc_mock.id = 1234
2405 1
        self.napp.circuits = {"1234": evc_mock}
2406 1
        payload = {
2407
            "circuit_ids": ["1234"],
2408
            "metadata1": 1,
2409
            "metadata2": 2
2410
        }
2411 1
        response = await self.api_client.post(
2412
            f"{self.base_endpoint}/v2/evc/metadata",
2413
            json=payload
2414
        )
2415 1
        assert response.status_code == 201
2416 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2417 1
        ids = payload.pop("circuit_ids")
2418 1
        assert args[0] == ids
2419 1
        assert args[1] == payload
2420 1
        assert args[2] == "add"
2421 1
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2422 1
        assert calls == 1
2423 1
        evc_mock.extend_metadata.assert_called_with(payload)
2424
2425 1
    async def test_add_bulk_metadata_empty_list(self):
2426
        """Test add_bulk_metadata method empty list"""
2427 1
        self.napp.controller.loop = asyncio.get_running_loop()
2428 1
        evc_mock = create_autospec(EVC)
2429 1
        evc_mock.id = 1234
2430 1
        self.napp.circuits = {"1234": evc_mock}
2431 1
        payload = {
2432
            "circuit_ids": [],
2433
            "metadata1": 1,
2434
            "metadata2": 2
2435
        }
2436 1
        response = await self.api_client.post(
2437
            f"{self.base_endpoint}/v2/evc/metadata",
2438
            json=payload
2439
        )
2440
        assert response.status_code == 400
2441
        assert "invalid" in response.json()["description"]
2442
2443 1
    async def test_add_bulk_metadata_no_id(self):
2444
        """Test add_bulk_metadata with unknown evc id"""
2445 1
        self.napp.controller.loop = asyncio.get_running_loop()
2446 1
        evc_mock = create_autospec(EVC)
2447 1
        evc_mock.id = 1234
2448 1
        self.napp.circuits = {"1234": evc_mock}
2449 1
        payload = {
2450
            "circuit_ids": ["1234", "4567"]
2451
        }
2452 1
        response = await self.api_client.post(
2453
            f"{self.base_endpoint}/v2/evc/metadata",
2454
            json=payload
2455
        )
2456
        assert response.status_code == 404
2457
2458 1
    async def test_add_bulk_metadata_no_circuits(self):
2459
        """Test add_bulk_metadata without circuit_ids"""
2460 1
        self.napp.controller.loop = asyncio.get_running_loop()
2461 1
        evc_mock = create_autospec(EVC)
2462 1
        evc_mock.id = 1234
2463 1
        self.napp.circuits = {"1234": evc_mock}
2464 1
        payload = {
2465
            "metadata": "data"
2466
        }
2467 1
        response = await self.api_client.post(
2468
            f"{self.base_endpoint}/v2/evc/metadata",
2469
            json=payload
2470
        )
2471
        assert response.status_code == 400
2472
2473 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...
2474
        """Test delete_metadata method"""
2475 1
        self.napp.controller.loop = asyncio.get_running_loop()
2476 1
        evc_mock = create_autospec(EVC)
2477 1
        evc_mock.id = 1234
2478 1
        self.napp.circuits = {"1234": evc_mock}
2479 1
        payload = {
2480
            "circuit_ids": ["1234"]
2481
        }
2482 1
        response = await self.api_client.request(
2483
            "DELETE",
2484
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2485
            json=payload
2486
        )
2487 1
        assert response.status_code == 200
2488 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2489 1
        assert args[0] == payload["circuit_ids"]
2490 1
        assert args[1] == {"metadata1": ""}
2491 1
        assert args[2] == "del"
2492 1
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2493 1
        assert calls == 1
2494 1
        assert evc_mock.remove_metadata.call_count == 1
2495
2496 1
    async def test_delete_bulk_metadata_error(self):
2497
        """Test bulk_delete_metadata with ciruit erroring"""
2498 1
        self.napp.controller.loop = asyncio.get_running_loop()
2499 1
        evc_mock = create_autospec(EVC)
2500 1
        evcs = [evc_mock, evc_mock]
2501 1
        self.napp.circuits = dict(zip(["1", "2"], evcs))
2502 1
        payload = {"circuit_ids": ["1", "2", "3"]}
2503 1
        response = await self.api_client.request(
2504
            "DELETE",
2505
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2506
            json=payload
2507
        )
2508
        assert response.status_code == 404, response.data
2509
        assert response.json()["description"] == ["3"]
2510
2511 1
    async def test_use_uni_tags(self):
2512
        """Test _use_uni_tags"""
2513 1
        self.napp.controller.loop = asyncio.get_running_loop()
2514 1
        evc_mock = create_autospec(EVC)
2515 1
        evc_mock.uni_a = "uni_a_mock"
2516 1
        evc_mock.uni_z = "uni_z_mock"
2517 1
        self.napp._use_uni_tags(evc_mock)
2518 1
        assert evc_mock._use_uni_vlan.call_count == 2
2519 1
        assert evc_mock._use_uni_vlan.call_args[0][0] == evc_mock.uni_z
2520
2521
        # One UNI tag is not available
2522 1
        evc_mock._use_uni_vlan.side_effect = [KytosTagError(""), None]
2523 1
        with pytest.raises(KytosTagError):
2524 1
            self.napp._use_uni_tags(evc_mock)
2525 1
        assert evc_mock._use_uni_vlan.call_count == 3
2526 1
        assert evc_mock.make_uni_vlan_available.call_count == 0
2527
2528 1
        evc_mock._use_uni_vlan.side_effect = [None, KytosTagError("")]
2529 1
        with pytest.raises(KytosTagError):
2530 1
            self.napp._use_uni_tags(evc_mock)
2531 1
        assert evc_mock._use_uni_vlan.call_count == 5
2532 1
        assert evc_mock.make_uni_vlan_available.call_count == 1
2533
2534 1
    def test_check_no_tag_duplication(self):
2535
        """Test _check_no_tag_duplication"""
2536 1
        evc = MagicMock()
2537 1
        evc.check_no_tag_duplicate = MagicMock()
2538 1
        evc.archived = False
2539 1
        evc.id = "1"
2540 1
        self.napp.circuits = {"1": evc}
2541 1
        evc_id = "2"
2542 1
        uni_a = get_uni_mocked(valid=True)
2543 1
        uni_z = get_uni_mocked(valid=True)
2544 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2545 1
        assert evc.check_no_tag_duplicate.call_count == 0
2546
2547 1
        uni_a.user_tag = None
2548 1
        uni_z.user_tag = None
2549 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2550 1
        assert evc.check_no_tag_duplicate.call_count == 2
2551
2552 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, None)
2553 1
        assert evc.check_no_tag_duplicate.call_count == 3
2554
2555 1
        self.napp._check_no_tag_duplication(evc_id, None, None)
2556 1
        assert evc.check_no_tag_duplicate.call_count == 3
2557
2558 1
    @patch("napps.kytos.mef_eline.main.time")
2559 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_up")
2560 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_down")
2561 1
    def test_handle_on_interface_link_change(
2562
        self,
2563
        mock_down,
2564
        mock_up,
2565
        mock_time
2566
    ):
2567
        """Test handle_on_interface_link_change"""
2568 1
        mock_time.sleep.return_value = True
2569 1
        mock_intf = Mock()
2570 1
        mock_intf.id = "mock_intf"
2571
2572
        # Created/link_up
2573 1
        name = '.*.switch.interface.created'
2574 1
        content = {"interface": mock_intf}
2575 1
        event = KytosEvent(name=name, content=content)
2576 1
        self.napp.handle_on_interface_link_change(event)
2577 1
        assert mock_down.call_count == 0
2578 1
        assert mock_up.call_count == 1
2579
2580
        # Deleted/link_down
2581 1
        name = '.*.switch.interface.deleted'
2582 1
        event = KytosEvent(name=name, content=content)
2583 1
        self.napp.handle_on_interface_link_change(event)
2584 1
        assert mock_down.call_count == 1
2585 1
        assert mock_up.call_count == 1
2586
2587
        # Event delay
2588 1
        self.napp._intf_events[mock_intf.id]["last_acquired"] = "mock_time"
2589 1
        for _ in range(1, 6):
2590 1
            self.napp.handle_on_interface_link_change(event)
2591 1
        assert mock_down.call_count == 1
2592 1
        assert mock_up.call_count == 1
2593
2594 1
        self.napp._intf_events[mock_intf.id].pop("last_acquired")
2595 1
        self.napp.handle_on_interface_link_change(event)
2596 1
        assert mock_down.call_count == 2
2597 1
        assert mock_up.call_count == 1
2598
2599
        # Out of order event
2600 1
        event = KytosEvent(name=name, content=content)
2601 1
        self.napp._intf_events[mock_intf.id]["event"] = Mock(timestamp=now())
2602
2603 1
        self.napp.handle_on_interface_link_change(event)
2604 1
        assert mock_down.call_count == 2
2605
        assert mock_up.call_count == 1
2606