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

TestMain.test_handle_link_down()   B

Complexity

Conditions 1

Size

Total Lines 94
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 1

Importance

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

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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