Passed
Pull Request — master (#320)
by Vinicius
03:39
created

TestMain.test_update_circuit()   B

Complexity

Conditions 1

Size

Total Lines 152
Code Lines 110

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 52
CRAP Score 1

Importance

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