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

TestMain.test_delete_no_evc()   A

Complexity

Conditions 1

Size

Total Lines 8
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 7
nop 1
dl 0
loc 8
ccs 7
cts 7
cp 1
crap 1
rs 10
c 0
b 0
f 0
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