Passed
Pull Request — master (#473)
by Vinicius
03:59
created

TestMain.test_create_circuit_already_enabled()   B

Complexity

Conditions 1

Size

Total Lines 69
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 1.0016

Importance

Changes 0
Metric Value
cc 1
eloc 57
nop 10
dl 0
loc 69
ccs 30
cts 34
cp 0.8824
crap 1.0016
rs 8.4072
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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