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

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