Passed
Pull Request — master (#438)
by Italo Valcy
08:11
created

TestMain.test_cleanup_evcs_old_path()   A

Complexity

Conditions 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

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