Passed
Pull Request — master (#407)
by Vinicius
09:10 queued 05:00
created

TestMain.test_delete_metadata_no_evc()   A

Complexity

Conditions 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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