Passed
Pull Request — master (#697)
by
unknown
05:01
created

TestMain.test_handle_link_down()   B

Complexity

Conditions 1

Size

Total Lines 94
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 63
nop 1
dl 0
loc 94
ccs 43
cts 43
cp 1
crap 1
rs 8.2109
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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