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

TestMain.test_update_circuit_invalid_json()   B

Complexity

Conditions 1

Size

Total Lines 72
Code Lines 60

Duplication

Lines 72
Ratio 100 %

Code Coverage

Tests 34
CRAP Score 1.0005

Importance

Changes 0
Metric Value
cc 1
eloc 60
nop 10
dl 72
loc 72
ccs 34
cts 37
cp 0.9189
crap 1.0005
rs 8.309
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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