Passed
Push — master ( 71c496...12cb0f )
by Aldo
03:10 queued 15s
created

TestMain.test_delete_archived_evc()   B

Complexity

Conditions 1

Size

Total Lines 82
Code Lines 70

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 41
CRAP Score 1.0012

Importance

Changes 0
Metric Value
cc 1
eloc 70
nop 12
dl 0
loc 82
rs 7.9818
c 0
b 0
f 0
ccs 41
cts 46
cp 0.8913
crap 1.0012

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
    @patch("time.sleep", return_value=None)
1919 1
    @patch("napps.kytos.mef_eline.utils.emit_event")
1920 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1921 1
    def test_handle_link_down(
1922
        self, emit_main_mock, emit_utils_mock, _
1923
    ):
1924
        """Test handle_link_down method."""
1925 1
        uni = create_autospec(UNI)
1926 1
        evc1 = MagicMock(id="1", service_level=0, creation_time=1,
1927
                         metadata="mock", _active="true", _enabled="true",
1928
                         uni_a=uni, uni_z=uni)
1929 1
        evc1.name = "name"
1930 1
        evc1.is_affected_by_link.return_value = True
1931 1
        evc1.handle_link_down.return_value = True
1932 1
        evc1.failover_path = None
1933 1
        evc2 = MagicMock(id="2", service_level=6, creation_time=1)
1934 1
        evc2.is_affected_by_link.return_value = False
1935 1
        evc2.is_failover_path_affected_by_link.return_value = True
1936 1
        evc2.as_dict.return_value = {"id": "2"}
1937 1
        evc3 = MagicMock(id="3", service_level=5, creation_time=1,
1938
                         metadata="mock", _active="true", _enabled="true",
1939
                         uni_a=uni, uni_z=uni)
1940 1
        evc3.name = "name"
1941 1
        evc3.is_affected_by_link.return_value = True
1942 1
        evc3.handle_link_down.return_value = True
1943 1
        evc3.failover_path = None
1944 1
        evc4 = MagicMock(id="4", service_level=4, creation_time=1,
1945
                         metadata="mock", _active="true", _enabled="true",
1946
                         uni_a=uni, uni_z=uni)
1947 1
        evc4.name = "name"
1948 1
        evc4.is_affected_by_link.return_value = True
1949 1
        evc4.is_failover_path_affected_by_link.return_value = False
1950 1
        evc4.failover_path = ["2"]
1951 1
        evc4.get_failover_flows.return_value = {
1952
            "2": ["flow1", "flow2"],
1953
            "3": ["flow3", "flow4", "flow5", "flow6"],
1954
        }
1955 1
        evc4.as_dict.return_value = {"id": "4"}
1956 1
        evc5 = MagicMock(id="5", service_level=7, creation_time=1)
1957 1
        evc5.is_affected_by_link.return_value = True
1958 1
        evc5.is_failover_path_affected_by_link.return_value = False
1959 1
        evc5.failover_path = ["3"]
1960 1
        evc5.get_failover_flows.return_value = {
1961
            "4": ["flow7", "flow8"],
1962
            "5": ["flow9", "flow10"],
1963
        }
1964 1
        evc5.as_dict.return_value = {"id": "5"}
1965 1
        evc6 = MagicMock(id="6", service_level=8, creation_time=1,
1966
                         metadata="mock", _active="true", _enabled="true",
1967
                         uni_a=uni, uni_z=uni)
1968 1
        evc6.name = "name"
1969 1
        evc6.is_affected_by_link.return_value = True
1970 1
        evc6.is_failover_path_affected_by_link.return_value = False
1971 1
        evc6.failover_path = ["3"]
1972 1
        evc6.get_failover_flows.side_effect = AttributeError("err")
1973 1
        link = MagicMock(id="123")
1974 1
        event = KytosEvent(name="test", content={"link": link})
1975 1
        self.napp.circuits = {"1": evc1, "2": evc2, "3": evc3, "4": evc4,
1976
                              "5": evc5, "6": evc6}
1977 1
        self.napp.handle_link_down(event)
1978
1979 1
        assert evc5.service_level > evc4.service_level
1980
        # evc5 batched flows should be sent first
1981 1
        emit_utils_mock.assert_has_calls([
1982
            call(
1983
                self.napp.controller,
1984
                context="kytos.flow_manager",
1985
                name="flows.install",
1986
                content={
1987
                    "dpid": "4",
1988
                    "flow_dict": {"flows": ["flow7", "flow8"]},
1989
                    'force': True,
1990
                }
1991
            ),
1992
            call(
1993
                self.napp.controller,
1994
                context="kytos.flow_manager",
1995
                name="flows.install",
1996
                content={
1997
                    "dpid": "5",
1998
                    "flow_dict": {"flows": ["flow9", "flow10"]},
1999
                    'force': True,
2000
                }
2001
            ),
2002
            call(
2003
                self.napp.controller,
2004
                context="kytos.flow_manager",
2005
                name="flows.install",
2006
                content={
2007
                    "dpid": "2",
2008
                    "flow_dict": {"flows": ["flow1", "flow2"]},
2009
                    'force': True,
2010
                }
2011
            ),
2012
            call(
2013
                self.napp.controller,
2014
                context="kytos.flow_manager",
2015
                name="flows.install",
2016
                content={
2017
                    "dpid": "3",
2018
                    "flow_dict": {
2019
                        "flows": ["flow3", "flow4", "flow5", "flow6"]
2020
                    },
2021
                    'force': True,
2022
                }
2023
            )
2024
        ])
2025 1
        event_name = "evc_affected_by_link_down"
2026 1
        assert evc3.service_level > evc1.service_level
2027
        # evc3 should be handled before evc1
2028 1
        emit_main_mock.assert_has_calls([
2029
            call(self.napp.controller, event_name, content={
2030
                "link": link,
2031
                "id": "6",
2032
                "evc_id": "6",
2033
                "name": "name",
2034
                "metadata": "mock",
2035
                "active": "true",
2036
                "enabled": "true",
2037
                "uni_a": uni.as_dict(),
2038
                "uni_z": uni.as_dict(),
2039
            }),
2040
            call(self.napp.controller, event_name, content={
2041
                "link": link,
2042
                "evc_id": "3",
2043
                "id": "3",
2044
                "name": "name",
2045
                "metadata": "mock",
2046
                "active": "true",
2047
                "enabled": "true",
2048
                "uni_a": uni.as_dict(),
2049
                "uni_z": uni.as_dict(),
2050
            }),
2051
            call(self.napp.controller, event_name, content={
2052
                "link": link,
2053
                "evc_id": "1",
2054
                "id": "1",
2055
                "name": "name",
2056
                "metadata": "mock",
2057
                "active": "true",
2058
                "enabled": "true",
2059
                "uni_a": uni.as_dict(),
2060
                "uni_z": uni.as_dict(),
2061
            }),
2062
        ])
2063 1
        self.napp.mongo_controller.update_evcs.assert_called_with(
2064
            [{"id": "5"}, {"id": "4"}, {"id": "2"}]
2065
        )
2066 1
        event_name = "failover_link_down"
2067 1
        assert emit_main_mock.call_args_list[0][0][1] == event_name
2068
2069 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2070 1
    def test_handle_evc_affected_by_link_down(self, emit_event_mock):
2071
        """Test handle_evc_affected_by_link_down method."""
2072 1
        uni = create_autospec(UNI)
2073 1
        evc1 = MagicMock(
2074
            id="1",
2075
            metadata="data_mocked",
2076
            _active="true",
2077
            _enabled="false",
2078
            uni_a=uni,
2079
            uni_z=uni,
2080
        )
2081 1
        evc1.name = "name_mocked"
2082 1
        evc1.handle_link_down.return_value = True
2083 1
        evc2 = MagicMock(
2084
            id="2",
2085
            metadata="mocked_data",
2086
            _active="false",
2087
            _enabled="true",
2088
            uni_a=uni,
2089
            uni_z=uni,
2090
        )
2091 1
        evc2.name = "mocked_name"
2092 1
        evc2.handle_link_down.return_value = False
2093 1
        self.napp.circuits = {"1": evc1, "2": evc2}
2094
2095 1
        event = KytosEvent(name="e1", content={
2096
            "evc_id": "3",
2097
            "link": MagicMock(),
2098
        })
2099 1
        self.napp.handle_evc_affected_by_link_down(event)
2100 1
        emit_event_mock.assert_not_called()
2101 1
        event.content["evc_id"] = "1"
2102 1
        self.napp.handle_evc_affected_by_link_down(event)
2103 1
        emit_event_mock.assert_called_with(
2104
            self.napp.controller, "redeployed_link_down", content={
2105
                "id": "1",
2106
                "evc_id": "1",
2107
                "name": "name_mocked",
2108
                "metadata": "data_mocked",
2109
                "active": "true",
2110
                "enabled": "false",
2111
                "uni_a": uni.as_dict(),
2112
                "uni_z": uni.as_dict(),
2113
            }
2114
        )
2115
2116 1
        event.content["evc_id"] = "2"
2117 1
        self.napp.handle_evc_affected_by_link_down(event)
2118 1
        emit_event_mock.assert_called_with(
2119
            self.napp.controller, "error_redeploy_link_down", content={
2120
                "evc_id": "2",
2121
                "id": "2",
2122
                "name": "mocked_name",
2123
                "metadata": "mocked_data",
2124
                "active": "false",
2125
                "enabled": "true",
2126
                "uni_a": uni.as_dict(),
2127
                "uni_z": uni.as_dict(),
2128
            }
2129
        )
2130
2131 1
    def test_cleanup_evcs_old_path(self, monkeypatch):
2132
        """Test handle_cleanup_evcs_old_path method."""
2133 1
        current_path, map_evc_content, emit_event = [
2134
            MagicMock(), MagicMock(), MagicMock()
2135
        ]
2136 1
        send_flows, merge_flows, create_flows = [
2137
            MagicMock(), MagicMock(), MagicMock()
2138
        ]
2139 1
        monkeypatch.setattr(
2140
            "napps.kytos.mef_eline.main.map_evc_event_content",
2141
            map_evc_content
2142
        )
2143 1
        monkeypatch.setattr(
2144
            "napps.kytos.mef_eline.main.emit_event",
2145
            emit_event
2146
        )
2147 1
        monkeypatch.setattr(
2148
            "napps.kytos.mef_eline.main.send_flow_mods_event",
2149
            send_flows
2150
        )
2151 1
        monkeypatch.setattr(
2152
            "napps.kytos.mef_eline.main.merge_flow_dicts",
2153
            merge_flows
2154
        )
2155 1
        monkeypatch.setattr(
2156
            "napps.kytos.mef_eline.main.prepare_delete_flow",
2157
            create_flows
2158
        )
2159 1
        merge_flows.return_value = ['1', '2']
2160 1
        evc1 = create_autospec(EVC, id="1", old_path=["1"],
2161
                               current_path=current_path, lock=MagicMock())
2162 1
        evc2 = create_autospec(EVC, id="2", old_path=["2"],
2163
                               current_path=current_path, lock=MagicMock())
2164 1
        evc3 = create_autospec(EVC, id="3", old_path=[],
2165
                               current_path=[], lock=MagicMock())
2166
2167 1
        event = KytosEvent(name="e1", content={"evcs": [evc1, evc2, evc3]})
2168 1
        assert evc1.old_path
2169 1
        assert evc2.old_path
2170 1
        self.napp.handle_cleanup_evcs_old_path(event)
2171 1
        evc1._prepare_nni_flows.assert_called_with(["1"])
2172 1
        evc1._prepare_uni_flows.assert_called_with(["1"], skip_in=True)
2173 1
        evc2._prepare_nni_flows.assert_called_with(["2"])
2174 1
        evc2._prepare_uni_flows.assert_called_with(["2"], skip_in=True)
2175 1
        evc3._prepare_nni_flows.assert_not_called()
2176 1
        evc3._prepare_uni_flows.assert_not_called()
2177 1
        assert create_flows.call_count == 4
2178 1
        assert emit_event.call_count == 1
2179 1
        assert emit_event.call_args[0][1] == "failover_old_path"
2180 1
        assert map_evc_content.call_args[1]['removed_flows'] == ['1', '2']
2181 1
        assert len(emit_event.call_args[1]["content"]) == 2
2182 1
        assert send_flows.call_count == 1
2183 1
        assert send_flows.call_args[0][1] == ['1', '2']
2184 1
        assert send_flows.call_args[0][2] == 'delete'
2185 1
        assert merge_flows.call_count == 4
2186 1
        assert not evc1.old_path
2187 1
        assert not evc2.old_path
2188
2189 1
    async def test_add_metadata(self):
2190
        """Test method to add metadata"""
2191 1
        self.napp.controller.loop = asyncio.get_running_loop()
2192 1
        evc_mock = create_autospec(EVC)
2193 1
        evc_mock.metadata = {}
2194 1
        evc_mock.id = 1234
2195 1
        self.napp.circuits = {"1234": evc_mock}
2196
2197 1
        payload = {"metadata1": 1, "metadata2": 2}
2198 1
        response = await self.api_client.post(
2199
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2200
            json=payload
2201
        )
2202
2203 1
        assert response.status_code == 201
2204 1
        evc_mock.extend_metadata.assert_called_with(payload)
2205
2206 1
    async def test_add_metadata_malformed_json(self):
2207
        """Test method to add metadata with a malformed json"""
2208 1
        self.napp.controller.loop = asyncio.get_running_loop()
2209 1
        payload = b'{"metadata1": 1, "metadata2": 2,}'
2210 1
        response = await self.api_client.post(
2211
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2212
            content=payload,
2213
            headers={"Content-Type": "application/json"}
2214
        )
2215
2216
        assert response.status_code == 400
2217
        assert "body contains invalid API" in response.json()["description"]
2218
2219 1
    async def test_add_metadata_no_body(self):
2220
        """Test method to add metadata with no body"""
2221 1
        self.napp.controller.loop = asyncio.get_running_loop()
2222 1
        response = await self.api_client.post(
2223
            f"{self.base_endpoint}/v2/evc/1234/metadata"
2224
        )
2225
        assert response.status_code == 400
2226
        assert response.json()["description"] == \
2227
            "Missing required request body"
2228
2229 1
    async def test_add_metadata_no_evc(self):
2230
        """Test method to add metadata with no evc"""
2231 1
        self.napp.controller.loop = asyncio.get_running_loop()
2232 1
        payload = {"metadata1": 1, "metadata2": 2}
2233 1
        response = await self.api_client.post(
2234
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2235
            json=payload,
2236
        )
2237
        assert response.status_code == 404
2238
        assert response.json()["description"] == \
2239
            "circuit_id 1234 not found."
2240
2241 1
    async def test_add_metadata_wrong_content_type(self):
2242
        """Test method to add metadata with wrong content type"""
2243 1
        self.napp.controller.loop = asyncio.get_running_loop()
2244 1
        payload = {"metadata1": 1, "metadata2": 2}
2245 1
        response = await self.api_client.post(
2246
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2247
            data=payload,
2248
            headers={"Content-Type": "application/xml"}
2249
        )
2250
        assert response.status_code == 415
2251
        assert "application/xml" in response.json()["description"]
2252
2253 1
    async def test_get_metadata(self):
2254
        """Test method to get metadata"""
2255 1
        evc_mock = create_autospec(EVC)
2256 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2257 1
        evc_mock.id = 1234
2258 1
        self.napp.circuits = {"1234": evc_mock}
2259
2260 1
        response = await self.api_client.get(
2261
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2262
        )
2263 1
        assert response.status_code == 200
2264 1
        assert response.json() == {"metadata": evc_mock.metadata}
2265
2266 1
    async def test_delete_metadata(self):
2267
        """Test method to delete metadata"""
2268 1
        evc_mock = create_autospec(EVC)
2269 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2270 1
        evc_mock.id = 1234
2271 1
        self.napp.circuits = {"1234": evc_mock}
2272
2273 1
        response = await self.api_client.delete(
2274
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2275
        )
2276 1
        assert response.status_code == 200
2277
2278 1
    async def test_delete_metadata_no_evc(self):
2279
        """Test method to delete metadata with no evc"""
2280 1
        response = await self.api_client.delete(
2281
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2282
        )
2283
        assert response.status_code == 404
2284
        assert response.json()["description"] == \
2285
            "circuit_id 1234 not found."
2286
2287 1
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
2288 1
    def test_load_all_evcs(self, load_evc_mock):
2289
        """Test load_evcs method"""
2290 1
        mock_circuits = {
2291
            'circuits': {
2292
                1: 'circuit_1',
2293
                2: 'circuit_2',
2294
                3: 'circuit_3',
2295
                4: 'circuit_4'
2296
            }
2297
        }
2298 1
        self.napp.mongo_controller.get_circuits.return_value = mock_circuits
2299 1
        self.napp.circuits = {2: 'circuit_2', 3: 'circuit_3'}
2300 1
        self.napp.load_all_evcs()
2301 1
        load_evc_mock.assert_has_calls([call('circuit_1'), call('circuit_4')])
2302 1
        assert self.napp.controller.buffers.app.put.call_count > 1
2303 1
        call_args = self.napp.controller.buffers.app.put.call_args[0]
2304 1
        assert call_args[0].name == "kytos/mef_eline.evcs_loaded"
2305 1
        assert dict(call_args[0].content) == mock_circuits["circuits"]
2306 1
        timeout_d = {"timeout": 1}
2307 1
        assert self.napp.controller.buffers.app.put.call_args[1] == timeout_d
2308
2309 1
    @patch('napps.kytos.mef_eline.main.Main._evc_from_dict')
2310 1
    def test_load_evc(self, evc_from_dict_mock):
2311
        """Test _load_evc method"""
2312
        # pylint: disable=protected-access
2313
        # case 1: early return with ValueError exception
2314 1
        evc_from_dict_mock.side_effect = ValueError("err")
2315 1
        evc_dict = MagicMock()
2316 1
        assert not self.napp._load_evc(evc_dict)
2317
2318
        # case 2: early return with KytosTagError exception
2319 1
        evc_from_dict_mock.side_effect = KytosTagError("")
2320 1
        assert not self.napp._load_evc(evc_dict)
2321
2322
        # case 3: archived evc
2323 1
        evc = MagicMock()
2324 1
        evc.archived = True
2325 1
        evc_from_dict_mock.side_effect = None
2326 1
        evc_from_dict_mock.return_value = evc
2327 1
        assert not self.napp._load_evc(evc_dict)
2328
2329
        # case 4: success creating
2330 1
        evc.archived = False
2331 1
        evc.id = 1
2332 1
        self.napp.sched = MagicMock()
2333
2334 1
        result = self.napp._load_evc(evc_dict)
2335 1
        assert result == evc
2336 1
        self.napp.sched.add.assert_called_with(evc)
2337 1
        assert self.napp.circuits[1] == evc
2338
2339 1
    def test_handle_flow_mod_error(self):
2340
        """Test handle_flow_mod_error method"""
2341 1
        flow = MagicMock()
2342 1
        flow.cookie = 0xaa00000000000011
2343 1
        event = MagicMock()
2344 1
        event.content = {'flow': flow, 'error_command': 'add'}
2345 1
        evc = create_autospec(EVC)
2346 1
        evc.remove_current_flows = MagicMock()
2347 1
        evc.lock = MagicMock()
2348 1
        self.napp.circuits = {"00000000000011": evc}
2349 1
        self.napp.handle_flow_mod_error(event)
2350 1
        evc.remove_current_flows.assert_called_once()
2351
2352 1
    @patch("kytos.core.Controller.get_interface_by_id")
2353 1
    def test_uni_from_dict(self, _get_interface_by_id_mock):
2354
        """Test _uni_from_dict method."""
2355
        # pylint: disable=protected-access
2356
        # case1: early return on empty dict
2357 1
        assert not self.napp._uni_from_dict(None)
2358
2359
        # case2: invalid interface raises ValueError
2360 1
        _get_interface_by_id_mock.return_value = None
2361 1
        uni_dict = {
2362
            "interface_id": "00:01:1",
2363
            "tag": {"tag_type": 'vlan', "value": 81},
2364
        }
2365 1
        with pytest.raises(ValueError):
2366 1
            self.napp._uni_from_dict(uni_dict)
2367
2368
        # case3: success creation
2369 1
        uni_mock = get_uni_mocked(switch_id="00:01")
2370 1
        _get_interface_by_id_mock.return_value = uni_mock.interface
2371 1
        uni = self.napp._uni_from_dict(uni_dict)
2372 1
        assert uni == uni_mock
2373
2374
        # case4: success creation of tag list
2375 1
        uni_dict["tag"]["value"] = [[1, 10]]
2376 1
        uni = self.napp._uni_from_dict(uni_dict)
2377 1
        assert isinstance(uni.user_tag, TAGRange)
2378
2379
        # case5: success creation without tag
2380 1
        uni_mock.user_tag = None
2381 1
        del uni_dict["tag"]
2382 1
        uni = self.napp._uni_from_dict(uni_dict)
2383 1
        assert uni == uni_mock
2384
2385 1
    def test_handle_flow_delete(self):
2386
        """Test handle_flow_delete method"""
2387 1
        flow = MagicMock()
2388 1
        flow.cookie = 0xaa00000000000011
2389 1
        event = MagicMock()
2390 1
        event.content = {'flow': flow}
2391 1
        evc = create_autospec(EVC)
2392 1
        evc.set_flow_removed_at = MagicMock()
2393 1
        self.napp.circuits = {"00000000000011": evc}
2394 1
        self.napp.handle_flow_delete(event)
2395 1
        evc.set_flow_removed_at.assert_called_once()
2396
2397 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...
2398
        """Test add_bulk_metadata method"""
2399 1
        self.napp.controller.loop = asyncio.get_running_loop()
2400 1
        evc_mock = create_autospec(EVC)
2401 1
        evc_mock.id = 1234
2402 1
        self.napp.circuits = {"1234": evc_mock}
2403 1
        payload = {
2404
            "circuit_ids": ["1234"],
2405
            "metadata1": 1,
2406
            "metadata2": 2
2407
        }
2408 1
        response = await self.api_client.post(
2409
            f"{self.base_endpoint}/v2/evc/metadata",
2410
            json=payload
2411
        )
2412 1
        assert response.status_code == 201
2413 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2414 1
        ids = payload.pop("circuit_ids")
2415 1
        assert args[0] == ids
2416 1
        assert args[1] == payload
2417 1
        assert args[2] == "add"
2418 1
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2419 1
        assert calls == 1
2420 1
        evc_mock.extend_metadata.assert_called_with(payload)
2421
2422 1
    async def test_add_bulk_metadata_empty_list(self):
2423
        """Test add_bulk_metadata method empty list"""
2424 1
        self.napp.controller.loop = asyncio.get_running_loop()
2425 1
        evc_mock = create_autospec(EVC)
2426 1
        evc_mock.id = 1234
2427 1
        self.napp.circuits = {"1234": evc_mock}
2428 1
        payload = {
2429
            "circuit_ids": [],
2430
            "metadata1": 1,
2431
            "metadata2": 2
2432
        }
2433 1
        response = await self.api_client.post(
2434
            f"{self.base_endpoint}/v2/evc/metadata",
2435
            json=payload
2436
        )
2437
        assert response.status_code == 400
2438
        assert "invalid" in response.json()["description"]
2439
2440 1
    async def test_add_bulk_metadata_no_id(self):
2441
        """Test add_bulk_metadata with unknown evc id"""
2442 1
        self.napp.controller.loop = asyncio.get_running_loop()
2443 1
        evc_mock = create_autospec(EVC)
2444 1
        evc_mock.id = 1234
2445 1
        self.napp.circuits = {"1234": evc_mock}
2446 1
        payload = {
2447
            "circuit_ids": ["1234", "4567"]
2448
        }
2449 1
        response = await self.api_client.post(
2450
            f"{self.base_endpoint}/v2/evc/metadata",
2451
            json=payload
2452
        )
2453
        assert response.status_code == 404
2454
2455 1
    async def test_add_bulk_metadata_no_circuits(self):
2456
        """Test add_bulk_metadata without circuit_ids"""
2457 1
        self.napp.controller.loop = asyncio.get_running_loop()
2458 1
        evc_mock = create_autospec(EVC)
2459 1
        evc_mock.id = 1234
2460 1
        self.napp.circuits = {"1234": evc_mock}
2461 1
        payload = {
2462
            "metadata": "data"
2463
        }
2464 1
        response = await self.api_client.post(
2465
            f"{self.base_endpoint}/v2/evc/metadata",
2466
            json=payload
2467
        )
2468
        assert response.status_code == 400
2469
2470 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...
2471
        """Test delete_metadata method"""
2472 1
        self.napp.controller.loop = asyncio.get_running_loop()
2473 1
        evc_mock = create_autospec(EVC)
2474 1
        evc_mock.id = 1234
2475 1
        self.napp.circuits = {"1234": evc_mock}
2476 1
        payload = {
2477
            "circuit_ids": ["1234"]
2478
        }
2479 1
        response = await self.api_client.request(
2480
            "DELETE",
2481
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2482
            json=payload
2483
        )
2484 1
        assert response.status_code == 200
2485 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2486 1
        assert args[0] == payload["circuit_ids"]
2487 1
        assert args[1] == {"metadata1": ""}
2488 1
        assert args[2] == "del"
2489 1
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2490 1
        assert calls == 1
2491 1
        assert evc_mock.remove_metadata.call_count == 1
2492
2493 1
    async def test_delete_bulk_metadata_error(self):
2494
        """Test bulk_delete_metadata with ciruit erroring"""
2495 1
        self.napp.controller.loop = asyncio.get_running_loop()
2496 1
        evc_mock = create_autospec(EVC)
2497 1
        evcs = [evc_mock, evc_mock]
2498 1
        self.napp.circuits = dict(zip(["1", "2"], evcs))
2499 1
        payload = {"circuit_ids": ["1", "2", "3"]}
2500 1
        response = await self.api_client.request(
2501
            "DELETE",
2502
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2503
            json=payload
2504
        )
2505
        assert response.status_code == 404, response.data
2506
        assert response.json()["description"] == ["3"]
2507
2508 1
    async def test_use_uni_tags(self):
2509
        """Test _use_uni_tags"""
2510 1
        self.napp.controller.loop = asyncio.get_running_loop()
2511 1
        evc_mock = create_autospec(EVC)
2512 1
        evc_mock.uni_a = "uni_a_mock"
2513 1
        evc_mock.uni_z = "uni_z_mock"
2514 1
        self.napp._use_uni_tags(evc_mock)
2515 1
        assert evc_mock._use_uni_vlan.call_count == 2
2516 1
        assert evc_mock._use_uni_vlan.call_args[0][0] == evc_mock.uni_z
2517
2518
        # One UNI tag is not available
2519 1
        evc_mock._use_uni_vlan.side_effect = [KytosTagError(""), None]
2520 1
        with pytest.raises(KytosTagError):
2521 1
            self.napp._use_uni_tags(evc_mock)
2522 1
        assert evc_mock._use_uni_vlan.call_count == 3
2523 1
        assert evc_mock.make_uni_vlan_available.call_count == 0
2524
2525 1
        evc_mock._use_uni_vlan.side_effect = [None, KytosTagError("")]
2526 1
        with pytest.raises(KytosTagError):
2527 1
            self.napp._use_uni_tags(evc_mock)
2528 1
        assert evc_mock._use_uni_vlan.call_count == 5
2529 1
        assert evc_mock.make_uni_vlan_available.call_count == 1
2530
2531 1
    def test_check_no_tag_duplication(self):
2532
        """Test _check_no_tag_duplication"""
2533 1
        evc = MagicMock()
2534 1
        evc.check_no_tag_duplicate = MagicMock()
2535 1
        evc.archived = False
2536 1
        evc.id = "1"
2537 1
        self.napp.circuits = {"1": evc}
2538 1
        evc_id = "2"
2539 1
        uni_a = get_uni_mocked(valid=True)
2540 1
        uni_z = get_uni_mocked(valid=True)
2541 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2542 1
        assert evc.check_no_tag_duplicate.call_count == 0
2543
2544 1
        uni_a.user_tag = None
2545 1
        uni_z.user_tag = None
2546 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2547 1
        assert evc.check_no_tag_duplicate.call_count == 2
2548
2549 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, None)
2550 1
        assert evc.check_no_tag_duplicate.call_count == 3
2551
2552 1
        self.napp._check_no_tag_duplication(evc_id, None, None)
2553 1
        assert evc.check_no_tag_duplicate.call_count == 3
2554
2555 1
    @patch("napps.kytos.mef_eline.main.time")
2556 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_up")
2557 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_down")
2558 1
    def test_handle_on_interface_link_change(
2559
        self,
2560
        mock_down,
2561
        mock_up,
2562
        mock_time
2563
    ):
2564
        """Test handle_on_interface_link_change"""
2565 1
        mock_time.sleep.return_value = True
2566 1
        mock_intf = Mock()
2567 1
        mock_intf.id = "mock_intf"
2568
2569
        # Created/link_up
2570 1
        name = '.*.switch.interface.created'
2571 1
        content = {"interface": mock_intf}
2572 1
        event = KytosEvent(name=name, content=content)
2573 1
        self.napp.handle_on_interface_link_change(event)
2574 1
        assert mock_down.call_count == 0
2575 1
        assert mock_up.call_count == 1
2576
2577
        # Deleted/link_down
2578 1
        name = '.*.switch.interface.deleted'
2579 1
        event = KytosEvent(name=name, content=content)
2580 1
        self.napp.handle_on_interface_link_change(event)
2581 1
        assert mock_down.call_count == 1
2582 1
        assert mock_up.call_count == 1
2583
2584
        # Event delay
2585 1
        self.napp._intf_events[mock_intf.id]["last_acquired"] = "mock_time"
2586 1
        for _ in range(1, 6):
2587 1
            self.napp.handle_on_interface_link_change(event)
2588 1
        assert mock_down.call_count == 1
2589 1
        assert mock_up.call_count == 1
2590
2591 1
        self.napp._intf_events[mock_intf.id].pop("last_acquired")
2592 1
        self.napp.handle_on_interface_link_change(event)
2593 1
        assert mock_down.call_count == 2
2594 1
        assert mock_up.call_count == 1
2595
2596
        # Out of order event
2597 1
        event = KytosEvent(name=name, content=content)
2598 1
        self.napp._intf_events[mock_intf.id]["event"] = Mock(timestamp=now())
2599
2600 1
        self.napp.handle_on_interface_link_change(event)
2601 1
        assert mock_down.call_count == 2
2602
        assert mock_up.call_count == 1
2603