Passed
Pull Request — master (#320)
by Vinicius
06:19
created

TestMain.test_update_circuit_invalid_json()   B

Complexity

Conditions 1

Size

Total Lines 64
Code Lines 52

Duplication

Lines 64
Ratio 100 %

Code Coverage

Tests 31
CRAP Score 1

Importance

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