Test Failed
Pull Request — master (#697)
by
unknown
06:22 queued 01:48
created

TestMain.test_update_circuit_invalid_path()   B

Complexity

Conditions 1

Size

Total Lines 84
Code Lines 69

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 1.0125

Importance

Changes 0
Metric Value
cc 1
eloc 69
nop 12
dl 0
loc 84
ccs 33
cts 43
cp 0.7674
crap 1.0125
rs 8.0145
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
"""Module to test the main napp file."""
2 1
import asyncio
3 1
from unittest.mock import (AsyncMock, MagicMock, Mock, call,
4
                           create_autospec, patch)
5
6 1
import pytest
7 1
from kytos.lib.helpers import get_controller_mock, get_test_client
8 1
from kytos.core.helpers import now
9 1
from kytos.core.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 1
16
17
async def test_on_table_enabled():
18 1
    """Test on_table_enabled"""
19
    # pylint: disable=import-outside-toplevel
20
    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 1
26
    # Succesfully setting table groups
27
    content = {"mef_eline": {"epl": 2}}
28 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
29 1
                       content=content)
30
    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 1
35
    # Failure at setting table groups
36
    content = {"mef_eline": {"unknown": 123}}
37 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
38 1
                       content=content)
39
    await napp.on_table_enabled(event)
40 1
    assert controller.buffers.app.aput.call_count == 1
41 1
42
    # Failure with early return
43
    content = {}
44 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
45 1
                       content=content)
46
    await napp.on_table_enabled(event)
47 1
    assert controller.buffers.app.aput.call_count == 1
48 1
49
50
# pylint: disable=too-many-public-methods, too-many-lines
51
# pylint: disable=too-many-arguments,too-many-locals
52
class TestMain:
53 1
    """Test the Main class."""
54
55
    def setup_method(self):
56 1
        """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
        patch("kytos.core.helpers.run_on_thread", lambda x: x).start()
66 1
        # pylint: disable=import-outside-toplevel
67
        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 1
74
    def test_get_event_listeners(self):
75 1
        """Verify all event listeners registered."""
76
        expected_events = [
77 1
            "kytos/core.shutdown",
78
            "kytos/core.shutdown.kytos/mef_eline",
79
            "kytos/topology.link_up",
80
            "kytos/topology.link_down",
81
        ]
82
        actual_events = self.napp.listeners()
83 1
84
        for _event in expected_events:
85 1
            assert _event in actual_events, _event
86 1
87
    @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 1
        """Test execute."""
91
        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 1
96
        # Test locked should return
97
        mock_execute_consistency.call_count = 0
98 1
        mock_log.info.call_count = 0
99 1
        # pylint: disable=protected-access
100
        self.napp._lock = MagicMock()
101 1
        self.napp._lock.locked.return_value = True
102 1
        # pylint: enable=protected-access
103
        self.napp.execute()
104 1
        mock_execute_consistency.assert_not_called()
105 1
        mock_log.info.assert_not_called()
106 1
107
    @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 1
        """Test execute_consistency."""
112
        (mongo_controller_upsert_mock, mock_settings) = args
113 1
114
        stored_circuits = {'1': {'name': 'circuit_1'},
115 1
                           '2': {'name': 'circuit_2'},
116
                           '3': {'name': 'circuit_3'}}
117
        mongo_controller_upsert_mock.return_value = True
118 1
        self.napp.mongo_controller.get_circuits.return_value = {
119 1
            "circuits": stored_circuits
120
        }
121
122
        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 1
140
        mock_check_list_traces.return_value = {
141 1
                                                1: True,
142
                                                2: False
143
                                            }
144
145
        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 1
152
    @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 1
        """Test execute and wait for setting."""
158
        (mongo_controller_upsert_mock, _, mock_settings) = args
159 1
160
        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 1
            "circuits": stored_circuits
164
        }
165
166
        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 1
179
        mock_check_list_traces.return_value = {1: False}
180 1
181
        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 1
186
    @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 1
        """
190
        Test the helper method that create an EVN from dict.
191
192
        Verify object creation with circuit data and schedule data.
193
        """
194
        _validate_mock.return_value = True
195 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
196 1
        payload = {
197 1
            "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
        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 1
220
    @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 1
        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
        _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 1
            "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
        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 1
270
    @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 1
        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
        _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 1
            "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
        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 1
324
    async def test_list_without_circuits(self):
325 1
        """Test if list circuits return 'no circuit stored.'."""
326
        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 1
333
    async def test_list_no_circuits_stored(self):
334 1
        """Test if list circuits return all circuits stored."""
335
        circuits = {"circuits": {}}
336 1
        self.napp.mongo_controller.get_circuits.return_value = circuits
337 1
338
        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 1
343 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 1
        """Test if list circuits return all circuits stored."""
345
        circuits = {
346 1
            'circuits':
347
            {"1": {"name": "circuit_1"}, "2": {"name": "circuit_2"}}
348
        }
349
        get_circuits = self.napp.mongo_controller.get_circuits
350 1
        get_circuits.return_value = circuits
351 1
352
        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 1
358 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 1
        """Test if list circuits only archived circuits."""
360
        circuits = {
361 1
            'circuits':
362
            {
363
                "1": {"name": "circuit_1", "archived": True},
364
            }
365
        }
366
        get_circuits = self.napp.mongo_controller.get_circuits
367 1
        get_circuits.return_value = circuits
368 1
369
        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 1
                                        metadata={"metadata.a": "1"})
373
        expected_result = {"1": circuits["circuits"]["1"]}
374 1
        assert response.json() == expected_result
375 1
376
    async def test_list_with_archived_circuits_all(self):
377 1
        """Test if list circuits return all circuits."""
378
        circuits = {
379 1
            'circuits': {
380
                "1": {"name": "circuit_1"},
381
                "2": {"name": "circuit_2", "archived": True},
382
            }
383
        }
384
        self.napp.mongo_controller.get_circuits.return_value = circuits
385 1
386
        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 1
391
    async def test_circuit_with_valid_id(self):
392 1
        """Test if get_circuit return the circuit attributes."""
393
        circuit = {"name": "circuit_1"}
394 1
        self.napp.mongo_controller.get_circuit.return_value = circuit
395 1
396
        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 1
401
    async def test_circuit_with_invalid_id(self):
402 1
        """Test if get_circuit return invalid circuit_id."""
403
        self.napp.mongo_controller.get_circuit.return_value = None
404 1
        url = f"{self.base_endpoint}/v2/evc/3"
405 1
        response = await self.api_client.get(url)
406 1
        expected_result = "circuit_id 3 not found"
407
        assert response.json()["description"] == expected_result
408
409
    @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 1
        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
        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 1
450
        url = f"{self.base_endpoint}/v2/evc/"
451 1
        payload = {
452 1
            "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
        response = await self.api_client.post(url, json=payload)
478 1
        current_data = response.json()
479 1
480
        # verify expected result from request
481
        assert 201 == response.status_code
482 1
        assert "circuit_id" in current_data
483 1
484
        # verify uni called
485
        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 1
489
        # verify validation called
490
        validate_mock.assert_called_once()
491 1
        validate_mock.assert_called_with(
492 1
            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
        mongo_controller_upsert_mock.assert_called_once()
503 1
504
        # verify evc as dict is called to save in the box
505
        evc_as_dict_mock.assert_called()
506 1
        # verify add circuit in sched
507
        sched_add_mock.assert_called_once()
508 1
509
    async def test_create_a_circuit_case_2(self):
510 1
        """Test create a new circuit trying to send request without a json."""
511
        self.napp.controller.loop = asyncio.get_running_loop()
512 1
        url = f"{self.base_endpoint}/v2/evc/"
513 1
514
        response = await self.api_client.post(url)
515 1
        current_data = response.json()
516
        assert 400 == response.status_code
517
        assert "Missing required request body" in current_data["description"]
518
519
    async def test_create_a_circuit_case_3(self):
520 1
        """Test create a new circuit trying to send request with an
521
        invalid json."""
522
        self.napp.controller.loop = asyncio.get_running_loop()
523 1
        url = f"{self.base_endpoint}/v2/evc/"
524 1
525
        response = await self.api_client.post(
526 1
            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
    @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 1
        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
        self.napp.controller.loop = asyncio.get_running_loop()
543 1
        # pylint: disable=too-many-locals
544
        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 1
548
        payload = {
549 1
            "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
        response = await self.api_client.post(url, json=payload)
562 1
        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
    async def test_create_a_circuit_invalid_queue_id(self):
572 1
        """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
        payload = {
577
            "name": "my evc1",
578
            "queue_id": 8,
579
            "uni_a": {
580 1
                "interface_id": "00:00:00:00:00:00:00:01:76",
581 1
                "tag": {"tag_type": 'vlan', "value": 80},
582 1
            },
583 1
            "uni_z": {
584 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
585 1
                "tag": {"tag_type": 'vlan', "value": 1},
586 1
            },
587 1
        }
588 1
        response = await self.api_client.post(url, json=payload)
589 1
        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
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
596
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
597
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
598
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
599
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
600
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
601
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
602 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
603
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
604
    async def test_create_circuit_already_enabled(
605 1
        self,
606
        evc_as_dict_mock,
607 1
        validate_mock,
608 1
        mongo_controller_upsert_mock,
609
        uni_from_dict_mock,
610 1
        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
        self.napp.controller.loop = asyncio.get_running_loop()
619
        validate_mock.return_value = True
620
        mongo_controller_upsert_mock.return_value = True
621
        sched_add_mock.return_value = True
622 1
        evc_deploy_mock.return_value = True
623
        mock_tags_equal.return_value = True
624
        mock_check_duplicate.return_value = True
625
        mock_use_uni_tags.side_effect = [
626
            None, KytosTagError("The EVC already exists.")
627
        ]
628
        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 1
636 1
        payload = {
637 1
            "name": "my evc1",
638 1
            "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
        evc_as_dict_mock.return_value = payload
650
        response = await self.api_client.post(
651
            f"{self.base_endpoint}/v2/evc/",
652 1
            json=payload
653 1
        )
654 1
        assert 201 == response.status_code
655 1
656 1
        response = await self.api_client.post(
657 1
            f"{self.base_endpoint}/v2/evc/",
658 1
            json=payload
659 1
        )
660
        current_data = response.json()
661
        expected_data = "The EVC already exists."
662 1
        assert current_data["description"] == expected_data
663 1
        assert 400 == response.status_code
664 1
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 1
        self,
669
        uni_from_dict_mock,
670 1
        mock_tags_equal
671
    ):
672
        """Test when neither primary path nor dynamic_backup_path is set."""
673
        self.napp.controller.loop = asyncio.get_running_loop()
674
        mock_tags_equal.return_value = True
675
        url = f"{self.base_endpoint}/v2/evc/"
676
        uni1 = create_autospec(UNI)
677
        uni2 = create_autospec(UNI)
678
        uni1.interface = create_autospec(Interface)
679
        uni2.interface = create_autospec(Interface)
680
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
681
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
682
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
683 1
684 1
        payload = {
685
            "name": "my evc1",
686
            "frequency": "* * * * *",
687
            "uni_a": {
688 1
                "interface_id": "00:00:00:00:00:00:00:01:1",
689
                "tag": {"tag_type": 'vlan', "value": 80},
690 1
            },
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
        response = await self.api_client.post(url, json=payload)
698
        current_data = response.json()
699 1
        expected_data = "The EVC must have a primary path "
700 1
        expected_data += "or allow dynamic paths."
701 1
        assert 400 == response.status_code, response.data
702
        assert current_data["description"] == expected_data
703
704
    @patch("napps.kytos.mef_eline.main.Main._evc_from_dict")
705
    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 1
            "name": "my evc1",
712 1
            "uni_a": {
713 1
                "interface_id": "00:00:00:00:00:00:00:01:1",
714 1
            },
715 1
            "uni_z": {
716 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
717
            },
718 1
        }
719
        response = await self.api_client.post(url, json=payload)
720
        assert response.status_code == 400, response.data
721
722
    async def test_redeploy_evc(self):
723
        """Test endpoint to redeploy an EVC."""
724
        evc1 = MagicMock()
725
        evc1.is_enabled.return_value = True
726
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
727
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
728
        response = await self.api_client.patch(url)
729
        evc1.remove_failover_flows.assert_called()
730
        evc1.remove_current_flows.assert_called_with(
731 1
            sync=False, return_path=True
732
        )
733
        assert response.status_code == 202, response.data
734
735
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
736
        url = url + "?try_avoid_same_s_vlan=false"
737
        response = await self.api_client.patch(url)
738 1
        evc1.remove_current_flows.assert_called_with(
739 1
            sync=False, return_path=False
740
        )
741 1
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
        evc1.remove_current_flows.assert_called_with(
746
            sync=False, return_path=True
747
        )
748
749
    async def test_redeploy_evc_disabled(self):
750
        """Test endpoint to redeploy an EVC."""
751
        evc1 = MagicMock()
752
        evc1.is_enabled.return_value = False
753 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
754
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
755
        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
    async def test_redeploy_evc_deleted(self):
761
        """Test endpoint to redeploy an EVC."""
762
        evc1 = MagicMock()
763
        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 1
        assert response.status_code == 404, response.data
768 1
769 1
    async def test_list_schedules__no_data_stored(self):
770 1
        """Test if list circuits return all circuits stored."""
771 1
        self.napp.mongo_controller.get_circuits.return_value = {"circuits": {}}
772
773
        url = f"{self.base_endpoint}/v2/evc/schedule"
774 1
775 1
        response = await self.api_client.get(url)
776 1
        assert response.status_code == 200
777
        assert not response.json()
778
779
    def _add_mongodb_schedule_data(self, data_mock):
780
        """Add schedule data to mongodb mock object."""
781
        circuits = {"circuits": {}}
782
        payload_1 = {
783
            "id": "aa:aa:aa",
784
            "name": "my evc1",
785 1
            "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 1
                {"id": "2", "frequency": "1 * * * *", "action": "remove"},
796 1
            ],
797 1
        }
798
        circuits["circuits"].update({"aa:aa:aa": payload_1})
799
        payload_2 = {
800
            "id": "bb:bb:bb",
801
            "name": "my second evc2",
802
            "uni_a": {
803 1
                "interface_id": "00:00:00:00:00:00:00:01:2",
804 1
                "tag": {"tag_type": 'vlan', "value": 90},
805 1
            },
806 1
            "uni_z": {
807 1
                "interface_id": "00:00:00:00:00:00:00:03:2",
808 1
                "tag": {"tag_type": 'vlan', "value": 100},
809 1
            },
810 1
            "circuit_scheduler": [
811 1
                {"id": "3", "frequency": "1 * * * *", "action": "create"},
812
                {"id": "4", "frequency": "2 * * * *", "action": "remove"},
813
            ],
814
        }
815
        circuits["circuits"].update({"bb:bb:bb": payload_2})
816
        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 1
            },
823
            "uni_z": {
824
                "interface_id": "00:00:00:00:00:00:00:04:2",
825 1
                "tag": {"tag_type": 'vlan', "value": 100},
826
            },
827 1
        }
828 1
        circuits["circuits"].update({"cc:cc:cc": payload_3})
829 1
        # Add one circuit to the mongodb.
830 1
        data_mock.return_value = circuits
831 1
832 1
    async def test_list_schedules_from_mongodb(self):
833 1
        """Test if list circuits return specific circuits stored."""
834
        self._add_mongodb_schedule_data(
835
            self.napp.mongo_controller.get_circuits
836 1
        )
837
838 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
839 1
840 1
        # Call URL
841 1
        response = await self.api_client.get(url)
842
        # Expected JSON data from response
843
        expected = [
844
            {
845 1
                "circuit_id": "aa:aa:aa",
846 1
                "schedule": {
847 1
                    "action": "create",
848 1
                    "frequency": "* * * * *",
849
                    "id": "1",
850
                },
851
                "schedule_id": "1",
852 1
            },
853
            {
854 1
                "circuit_id": "aa:aa:aa",
855 1
                "schedule": {
856 1
                    "action": "remove",
857 1
                    "frequency": "1 * * * *",
858 1
                    "id": "2",
859 1
                },
860 1
                "schedule_id": "2",
861 1
            },
862
            {
863 1
                "circuit_id": "bb:bb:bb",
864
                "schedule": {
865 1
                    "action": "create",
866 1
                    "frequency": "1 * * * *",
867 1
                    "id": "3",
868 1
                },
869 1
                "schedule_id": "3",
870
            },
871
            {
872 1
                "circuit_id": "bb:bb:bb",
873
                "schedule": {
874 1
                    "action": "remove",
875
                    "frequency": "2 * * * *",
876 1
                    "id": "4",
877
                },
878 1
                "schedule_id": "4",
879 1
            },
880 1
        ]
881
882 1
        assert response.status_code == 200
883
        assert expected == response.json()
884 1
885 1
    async def test_get_specific_schedule_from_mongodb(self):
886
        """Test get schedules from a circuit."""
887
        self._add_mongodb_schedule_data(
888
            self.napp.mongo_controller.get_circuits
889
        )
890
891
        requested_circuit_id = "bb:bb:bb"
892
        evc = self.napp.mongo_controller.get_circuits()
893
        evc = evc["circuits"][requested_circuit_id]
894
        self.napp.mongo_controller.get_circuit.return_value = evc
895
        url = f"{self.base_endpoint}/v2/evc/{requested_circuit_id}"
896
897
        # Call URL
898
        response = await self.api_client.get(url)
899
900
        # Expected JSON data from response
901 1
        expected = [
902 1
            {"action": "create", "frequency": "1 * * * *", "id": "3"},
903
            {"action": "remove", "frequency": "2 * * * *", "id": "4"},
904
        ]
905
906
        assert response.status_code == 200
907
        assert expected == response.json()["circuit_scheduler"]
908
909
    async def test_get_specific_schedules_from_mongodb_not_found(self):
910
        """Test get specific schedule ID that does not exist."""
911
        requested_id = "blah"
912
        self.napp.mongo_controller.get_circuit.return_value = None
913
        url = f"{self.base_endpoint}/v2/evc/{requested_id}"
914
915
        # Call URL
916
        response = await self.api_client.get(url)
917
918 1
        expected = "circuit_id blah not found"
919 1
        # Assert response not found
920
        assert response.status_code == 404
921
        assert expected == response.json()["description"]
922
923
    def _uni_from_dict_side_effect(self, uni_dict):
924
        interface_id = uni_dict.get("interface_id")
925
        tag_dict = uni_dict.get("tag")
926
        interface = Interface(interface_id, "0", MagicMock(id="1"))
927
        return UNI(interface, tag_dict)
928
929
    @patch("apscheduler.schedulers.background.BackgroundScheduler.add_job")
930
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
931 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
932
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
933 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
934
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
935 1
    async def test_create_schedule(
936
        self,
937 1
        validate_mock,
938
        evc_as_dict_mock,
939
        mongo_controller_upsert_mock,
940
        uni_from_dict_mock,
941 1
        sched_add_mock,
942
        scheduler_add_job_mock
943
    ):
944 1
        """Test create a circuit schedule."""
945
        self.napp.controller.loop = asyncio.get_running_loop()
946 1
        validate_mock.return_value = True
947
        mongo_controller_upsert_mock.return_value = True
948
        uni_from_dict_mock.side_effect = self._uni_from_dict_side_effect
949
        evc_as_dict_mock.return_value = {}
950
        sched_add_mock.return_value = True
951
952
        self._add_mongodb_schedule_data(
953
            self.napp.mongo_controller.get_circuits
954
        )
955
956
        requested_id = "bb:bb:bb"
957
        url = f"{self.base_endpoint}/v2/evc/schedule/"
958
959
        payload = {
960
            "circuit_id": requested_id,
961
            "schedule": {"frequency": "1 * * * *", "action": "create"},
962
            "metadata": {"metadata1": "test_data"},
963
        }
964
965
        # Call URL
966
        response = await self.api_client.post(url, json=payload)
967
        response_json = response.json()
968
969
        assert response.status_code == 201
970
        scheduler_add_job_mock.assert_called_once()
971
        mongo_controller_upsert_mock.assert_called_once()
972
        assert payload["schedule"]["frequency"] == response_json["frequency"]
973
        assert payload["schedule"]["action"] == response_json["action"]
974
        assert response_json["id"] is not None
975
976
        # Case 2: there is no schedule
977
        payload = {
978
              "circuit_id": "cc:cc:cc",
979
              "schedule": {
980
                "frequency": "1 * * * *",
981
                "action": "create"
982
              }
983
            }
984
        response = await self.api_client.post(url, json=payload)
985 1
        assert response.status_code == 201
986 1
987
    async def test_create_schedule_invalid_request(self):
988 1
        """Test create schedule API with invalid request."""
989
        self.napp.controller.loop = asyncio.get_running_loop()
990 1
        evc1 = MagicMock()
991
        self.napp.circuits = {'bb:bb:bb': evc1}
992
        url = f'{self.base_endpoint}/v2/evc/schedule/'
993
994 1
        # case 1: empty post
995 1
        response = await self.api_client.post(url, json={})
996 1
        assert response.status_code == 400
997 1
998 1
        # case 2: not a dictionary
999
        payload = []
1000
        response = await self.api_client.post(url, json=payload)
1001 1
        assert response.status_code == 400
1002
1003
        # case 3: missing circuit id
1004 1
        payload = {
1005
            "schedule": {
1006
                "frequency": "1 * * * *",
1007
                "action": "create"
1008
            }
1009 1
        }
1010 1
        response = await self.api_client.post(url, json=payload)
1011
        assert response.status_code == 400
1012 1
1013
        # case 4: missing schedule
1014 1
        payload = {
1015 1
            "circuit_id": "bb:bb:bb"
1016 1
        }
1017
        response = await self.api_client.post(url, json=payload)
1018
        assert response.status_code == 400
1019 1
1020
        # case 5: invalid circuit
1021
        payload = {
1022
            "circuit_id": "xx:xx:xx",
1023
            "schedule": {
1024
                "frequency": "1 * * * *",
1025
                "action": "create"
1026 1
            }
1027 1
        }
1028 1
        response = await self.api_client.post(url, json=payload)
1029 1
        assert response.status_code == 404
1030 1
1031
        # case 6: invalid json
1032 1
        response = await self.api_client.post(url, json="test")
1033 1
        assert response.status_code == 400
1034 1
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
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1040
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1041
    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 1
        scheduler_remove_job_mock
1049 1
    ):
1050 1
        """Test create a circuit schedule."""
1051 1
        self.napp.controller.loop = asyncio.get_running_loop()
1052 1
        mongo_payload_1 = {
1053 1
            "circuits": {
1054
                "aa:aa:aa": {
1055 1
                    "id": "aa:aa:aa",
1056
                    "name": "my evc1",
1057
                    "uni_a": {
1058
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1059 1
                        "tag": {"tag_type": 'vlan', "value": 80},
1060 1
                    },
1061
                    "uni_z": {
1062 1
                        "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 1
                            "action": "create"
1070 1
                        }
1071
                    ],
1072 1
                }
1073 1
            }
1074 1
        }
1075 1
1076 1
        validate_mock.return_value = True
1077 1
        mongo_controller_upsert_mock.return_value = True
1078
        sched_add_mock.return_value = True
1079
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1080 1
        evc_as_dict_mock.return_value = {}
1081
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1082
        scheduler_remove_job_mock.return_value = True
1083
1084
        requested_schedule_id = "1"
1085
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1086
1087 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1088 1
1089
        # Call URL
1090 1
        response = await self.api_client.patch(url, json=payload)
1091
        response_json = response.json()
1092 1
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
        assert payload["frequency"] == response_json["frequency"]
1097
        assert payload["action"] == response_json["action"]
1098 1
        assert response_json["id"] is not None
1099
1100
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1101
    async def test_update_no_schedule(
1102
        self, find_evc_by_schedule_id_mock
1103
    ):
1104
        """Test update a circuit schedule."""
1105
        self.napp.controller.loop = asyncio.get_running_loop()
1106
        url = f"{self.base_endpoint}/v2/evc/schedule/1"
1107
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1108
1109
        find_evc_by_schedule_id_mock.return_value = None, None
1110
1111
        response = await self.api_client.patch(url, json=payload)
1112
        assert response.status_code == 404
1113
1114
    @patch("apscheduler.schedulers.background.BackgroundScheduler.remove_job")
1115
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1116
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1117
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1118
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1119
    async def test_delete_schedule(self, *args):
1120
        """Test create a circuit schedule."""
1121
        (
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
        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 1
                    "uni_z": {
1139 1
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1140 1
                        "tag": {"tag_type": 'vlan', "value": 1},
1141 1
                    },
1142 1
                    "circuit_scheduler": [
1143 1
                        {
1144 1
                            "id": "1",
1145
                            "frequency": "* * * * *",
1146
                            "action": "create"
1147
                        }
1148
                    ],
1149
                }
1150
            }
1151
        }
1152
        validate_mock.return_value = True
1153
        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
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1157
        scheduler_remove_job_mock.return_value = True
1158
1159
        requested_schedule_id = "1"
1160
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1161
1162
        # Call URL
1163
        response = await self.api_client.delete(url)
1164
1165
        assert response.status_code == 200
1166
        scheduler_remove_job_mock.assert_called_once()
1167
        mongo_controller_upsert_mock.assert_called_once()
1168
        assert "Schedule removed" in f"{response.json()}"
1169
1170
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1171
    async def test_delete_schedule_not_found(self, mock_find_evc_by_sched):
1172
        """Test delete a circuit schedule - unexisting."""
1173
        mock_find_evc_by_sched.return_value = (None, False)
1174
        url = f'{self.base_endpoint}/v2/evc/schedule/1'
1175
        response = await self.api_client.delete(url)
1176
        assert response.status_code == 404
1177
1178
    def test_get_evcs_by_svc_level(self) -> None:
1179 1
        """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 1
                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
        assert evcs_by_level
1187 1
1188 1
        for evc, exp_level in zip(evcs_by_level, expected_levels):
1189
            assert evc.service_level == exp_level
1190 1
1191
        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
        for i in range(2):
1196 1
            assert evcs_by_level[i].creation_time == i
1197 1
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 1
1202
        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
    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 1
1213
    @patch('httpx.post')
1214 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1215
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1216
    @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
    @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 1
        _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
        self.napp.controller.loop = asyncio.get_running_loop()
1240
        mock_use_uni_tags.return_value = True
1241
        evc_deploy.return_value = True
1242
        interface_by_id_mock.return_value = get_uni_mocked().interface
1243
        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
        uni_from_dict_mock.side_effect = 2 * unis
1248
1249
        response = MagicMock()
1250
        response.status_code = 201
1251
        httpx_mock.return_value = response
1252
1253
        payloads = [
1254
            {
1255 1
                "name": "my evc1",
1256 1
                "uni_a": {
1257 1
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1258 1
                    "tag": {"tag_type": 'vlan', "value": 80},
1259 1
                },
1260 1
                "uni_z": {
1261
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1262 1
                    "tag": {"tag_type": 'vlan', "value": 1},
1263 1
                },
1264
                "dynamic_backup_path": True,
1265
            },
1266 1
            {
1267
                "primary_path": [
1268 1
                    {
1269 1
                        "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1270 1
                        "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1271 1
                    }
1272
                ]
1273 1
            },
1274 1
            {
1275
                "sb_priority": 3
1276 1
            },
1277 1
            {
1278 1
                # It works only with 'enabled' and not with 'enable'
1279
                "enabled": True
1280
            },
1281 1
            {
1282
                "sb_priority": 100
1283 1
            }
1284 1
        ]
1285
1286 1
        evc_as_dict_mock.return_value = payloads[0]
1287 1
        response = await self.api_client.post(
1288 1
            f"{self.base_endpoint}/v2/evc/",
1289 1
            json=payloads[0],
1290
        )
1291 1
        assert 201 == response.status_code
1292 1
1293
        evc_deploy.reset_mock()
1294 1
        evc_as_dict_mock.return_value = payloads[1]
1295
        current_data = response.json()
1296 1
        circuit_id = current_data["circuit_id"]
1297 1
        response = await self.api_client.patch(
1298 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1299 1
            json=payloads[1],
1300
        )
1301 1
        # evc_deploy.assert_called_once()
1302 1
        assert 200 == response.status_code
1303 1
1304
        evc_deploy.reset_mock()
1305 1
        evc_as_dict_mock.return_value = payloads[2]
1306 1
        response = await self.api_client.patch(
1307 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1308
            json=payloads[2],
1309 1
        )
1310
        evc_deploy.assert_not_called()
1311 1
        assert 200 == response.status_code
1312 1
1313 1
        evc_deploy.reset_mock()
1314
        evc_as_dict_mock.return_value = payloads[3]
1315
        response = await self.api_client.patch(
1316 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1317 1
            json=payloads[3],
1318 1
        )
1319 1
        evc_deploy.assert_called_once()
1320 1
        assert 200 == response.status_code
1321 1
1322 1
        evc_deploy.reset_mock()
1323 1
        response = await self.api_client.patch(
1324 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1325 1
            content=b'{"priority":5,}',
1326 1
            headers={"Content-Type": "application/json"}
1327 1
        )
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 1
        response = await self.api_client.patch(
1343 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1344 1
            json=payloads[4]
1345 1
        )
1346 1
        assert 200 == response.status_code
1347
        evc_deploy.assert_called_once()
1348
1349 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
    @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
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1356 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1357
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1358
    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
        self.napp.controller.loop = asyncio.get_running_loop()
1372
        validate_mock.return_value = True
1373
        mongo_controller_upsert_mock.return_value = True
1374
        sched_add_mock.return_value = True
1375
        evc_deploy_mock.return_value = True
1376
        mock_use_uni_tags.return_value = True
1377
        mock_tags_equal.return_value = True
1378
        mock_check_duplicate.return_value = True
1379
        uni1 = create_autospec(UNI)
1380
        uni2 = create_autospec(UNI)
1381
        uni1.interface = create_autospec(Interface)
1382
        uni2.interface = create_autospec(Interface)
1383
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1384
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1385
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1386
1387
        payload1 = {
1388
            "name": "my evc1",
1389 1
            "uni_a": {
1390 1
                "interface_id": "00:00:00:00:00:00:00:01:1",
1391
                "tag": {"tag_type": 'vlan', "value": 80},
1392
            },
1393
            "uni_z": {
1394 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
1395
                "tag": {"tag_type": 'vlan', "value": 1},
1396 1
            },
1397 1
            "dynamic_backup_path": True,
1398 1
        }
1399 1
1400 1
        payload2 = {
1401
            "dynamic_backup_path": False,
1402
        }
1403
1404
        evc_as_dict_mock.return_value = payload1
1405 1
        response = await self.api_client.post(
1406
            f"{self.base_endpoint}/v2/evc/",
1407 1
            json=payload1
1408 1
        )
1409 1
        assert 201 == response.status_code
1410
1411
        evc_as_dict_mock.return_value = payload2
1412
        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 1
            json=payload2
1417 1
        )
1418 1
        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
    @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
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1428
    @patch("napps.kytos.mef_eline.main.Main._link_from_dict")
1429
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1430
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1431
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1432
    @patch("napps.kytos.mef_eline.models.path.Path.is_valid")
1433
    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
        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
        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
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1463
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1464
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1465
1466
        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 1
                "tag": {"tag_type": 'vlan', "value": 1},
1475 1
            },
1476 1
            "dynamic_backup_path": True,
1477 1
        }
1478 1
1479 1
        payload2 = {
1480 1
            "primary_path": [
1481 1
                {
1482 1
                    "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1483 1
                    "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1484 1
                }
1485 1
            ]
1486 1
        }
1487 1
1488 1
        evc_as_dict_mock.return_value = payload1
1489
        response = await self.api_client.post(
1490 1
            f"{self.base_endpoint}/v2/evc/",
1491
            json=payload1,
1492
        )
1493
        assert 201 == response.status_code
1494
1495
        evc_as_dict_mock.return_value = payload2
1496
        current_data = response.json()
1497
        circuit_id = current_data["circuit_id"]
1498
        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 1
        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 1
        """Test _link_from_dict non existent intf."""
1509
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1510
        link_dict = {
1511
            "endpoint_a": {"id": "a"},
1512 1
            "endpoint_b": {"id": "b"}
1513
        }
1514 1
        with pytest.raises(ValueError):
1515 1
            self.napp._link_from_dict(link_dict, "current_path")
1516 1
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
        intf = MagicMock(id="01:1")
1521
        self.napp.controller.get_interface_by_id = MagicMock(return_value=intf)
1522
        link_dict = {
1523
            'id': 'mock_link',
1524
            'endpoint_a': {'id': '00:00:00:00:00:00:00:01:4'},
1525 1
            'endpoint_b': {'id': '00:00:00:00:00:00:00:05:2'},
1526 1
            'metadata': {'s_vlan': {'tag_type': 'vlan', 'value': 1}}
1527 1
        }
1528 1
        link = self.napp._link_from_dict(link_dict, "current_path")
1529 1
        assert link.metadata.get('s_vlan', None)
1530 1
1531 1
        link = self.napp._link_from_dict(link_dict, "failover_path")
1532 1
        assert link.metadata.get('s_vlan', None)
1533 1
1534 1
        link = self.napp._link_from_dict(link_dict, "primary_path")
1535 1
        assert link.metadata.get('s_vlan', None) is None
1536 1
1537
    def test_uni_from_dict_non_existent_intf(self):
1538
        """Test _link_from_dict non existent intf."""
1539
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1540
        uni_dict = {
1541
            "interface_id": "aaa",
1542
        }
1543
        with pytest.raises(ValueError):
1544
            self.napp._uni_from_dict(uni_dict)
1545
1546 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
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1548
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1549
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1550
    @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 1
        self,
1556 1
        mongo_controller_upsert_mock,
1557 1
        validate_mock,
1558 1
        uni_from_dict_mock,
1559 1
        sched_add_mock,
1560 1
        evc_deploy_mock,
1561 1
        mock_use_uni_tags,
1562 1
        mock_tags_equal,
1563 1
        mock_check_duplicate
1564 1
    ):
1565 1
        """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
        sched_add_mock.return_value = True
1569 1
        evc_deploy_mock.return_value = True
1570
        mock_use_uni_tags.return_value = True
1571
        mock_tags_equal.return_value = True
1572
        mock_check_duplicate.return_value = True
1573
        uni1 = create_autospec(UNI)
1574
        uni2 = create_autospec(UNI)
1575
        uni1.interface = create_autospec(Interface)
1576
        uni2.interface = create_autospec(Interface)
1577
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1578
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1579
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1580
        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 1
            },
1592 1
            "dynamic_backup_path": True,
1593
        }
1594
1595
        payload2 = {"dynamic_backup_path": False}
1596 1
1597
        response = await self.api_client.post(
1598 1
            f"{self.base_endpoint}/v2/evc/",
1599 1
            json=payload1,
1600 1
        )
1601 1
        assert 201 == response.status_code
1602
1603
        current_data = response.json()
1604
        circuit_id = current_data["circuit_id"]
1605
        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 1
        assert "application/json" in current_data["description"]
1611 1
1612 1
    async def test_delete_no_evc(self):
1613 1
        """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 1
        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
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
1622
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1623
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_uni_tags")
1624
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1625
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_current_flows")
1626
    @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
    async def test_delete_archived_evc(
1633 1
        self,
1634
        evc_as_dict_mock,
1635
        validate_mock,
1636
        mongo_controller_upsert_mock,
1637 1
        uni_from_dict_mock,
1638
        sched_add_mock,
1639
        evc_deploy_mock,
1640
        remove_current_flows_mock,
1641 1
        mock_use_uni,
1642 1
        mock_remove_tags,
1643
        mock_tags_equal,
1644 1
        mock_check_duplicate
1645
    ):
1646
        """Try to delete an archived EVC"""
1647
        self.napp.controller.loop = asyncio.get_running_loop()
1648
        validate_mock.return_value = True
1649
        mongo_controller_upsert_mock.return_value = True
1650
        sched_add_mock.return_value = True
1651
        evc_deploy_mock.return_value = True
1652
        mock_use_uni.return_value = True
1653
        mock_tags_equal.return_value = True
1654
        mock_check_duplicate.return_value = True
1655
        uni1 = create_autospec(UNI)
1656
        uni2 = create_autospec(UNI)
1657
        uni1.interface = create_autospec(Interface)
1658 1
        uni2.interface = create_autospec(Interface)
1659
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1660
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1661
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1662
1663
        payload1 = {
1664
            "name": "my evc1",
1665 1
            "uni_a": {
1666 1
                "interface_id": "00:00:00:00:00:00:00:01:1",
1667
                "tag": {"tag_type": 'vlan', "value": 80},
1668
            },
1669
            "uni_z": {
1670 1
                "interface_id": "00:00:00:00:00:00:00:02:2",
1671 1
                "tag": {"tag_type": 'vlan', "value": 1},
1672 1
            },
1673
            "dynamic_backup_path": True,
1674 1
        }
1675
1676
        evc_as_dict_mock.return_value = payload1
1677
        response = await self.api_client.post(
1678
            f"{self.base_endpoint}/v2/evc/",
1679
            json=payload1
1680
        )
1681
        assert 201 == response.status_code
1682 1
        assert len(self.napp.circuits) == 1
1683
        current_data = response.json()
1684 1
        circuit_id = current_data["circuit_id"]
1685 1
        self.napp.circuits[circuit_id].archive()
1686
1687
        response = await self.api_client.delete(
1688
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1689 1
        )
1690 1
        assert 200 == response.status_code
1691
        assert mock_remove_tags.call_count == 0
1692 1
        assert remove_current_flows_mock.call_count == 0
1693
        assert len(self.napp.circuits) == 0
1694
1695 1
        response = await self.api_client.delete(
1696 1
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1697 1
        )
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 1
1704 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1705
    async def test_delete_circuit(self, emit_event_mock):
1706 1
        """Test delete_circuit"""
1707 1
        evc = MagicMock()
1708
        evc.archived = False
1709 1
        circuit_id = '1'
1710 1
        self.napp.circuits[circuit_id] = evc
1711
        response = await self.api_client.delete(
1712 1
            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
        assert evc.disable.call_count == 1
1717
        evc.remove_current_flows.assert_called_once_with(
1718 1
            sync=False
1719 1
        )
1720
        evc.remove_failover_flows.assert_called_once_with(
1721 1
            sync=False
1722 1
        )
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 1
1729 1
    def test_handle_link_up(self):
1730
        """Test handle_link_up method."""
1731
        evc_mock = create_autospec(EVC)
1732
        evc_mock.service_level, evc_mock.creation_time = 0, 1
1733
        evc_mock.is_enabled = MagicMock(side_effect=[
1734
            True, False, True, True, True
1735
        ])
1736
        evc_mock.lock = MagicMock()
1737
        evc_mock.archived = False
1738
        evcs = [evc_mock, evc_mock, evc_mock]
1739
        event = KytosEvent(name="test", content={"link": "abc"})
1740
        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 1
1745 1
    def test_handle_link_down(
1746 1
        self
1747 1
    ):
1748 1
        """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 1
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
        evc3 = MagicMock(id="3")
1760
        evc3.is_affected_by_link.return_value = True
1761
        evc3.is_failover_path_affected_by_link.return_value = False
1762
1763
        evc4 = MagicMock(id="4")
1764
        evc4.is_affected_by_link.return_value = True
1765
        evc4.is_failover_path_affected_by_link.return_value = False
1766
1767
        default_swap_to_failover = [evc3, evc4]
1768
1769
        evc5 = MagicMock(id="5")
1770 1
        evc5.is_affected_by_link.return_value = False
1771
        evc5.is_failover_path_affected_by_link.return_value = True
1772 1
1773
        evc6 = MagicMock(id="6")
1774
        evc6.is_affected_by_link.return_value = False
1775
        evc6.is_failover_path_affected_by_link.return_value = True
1776 1
1777
        default_clear_failover = [evc5, evc6]
1778 1
1779 1
        self.napp.get_evcs_by_svc_level = MagicMock()
1780 1
1781
        self.napp.get_evcs_by_svc_level.return_value = [
1782
            evc1,
1783
            evc2,
1784
            evc3,
1785
            evc4,
1786
            evc5,
1787 1
            evc6,
1788
        ]
1789 1
1790 1
        self.napp.execute_swap_to_failover = MagicMock()
1791
1792
        swap_to_failover_success = [evc3]
1793
        swap_to_failover_failure = [evc4]
1794
1795
        self.napp.execute_swap_to_failover.return_value =\
1796 1
            swap_to_failover_success, swap_to_failover_failure
1797 1
1798 1
        self.napp.execute_clear_failover = MagicMock()
1799 1
1800 1
        clear_failover_success = [evc5, evc3]
1801 1
        clear_failover_failure = [evc6]
1802 1
1803 1
        self.napp.execute_clear_failover.return_value =\
1804 1
            clear_failover_success, clear_failover_failure
1805 1
1806 1
        self.napp.execute_undeploy = MagicMock()
1807 1
1808
        undeploy_success = [evc1, evc4, evc6]
1809
        undeploy_failure = [evc2]
1810
1811
        self.napp.execute_undeploy.return_value =\
1812
            undeploy_success, undeploy_failure
1813
1814
        link = MagicMock(id="123")
1815
        event = KytosEvent(name="test", content={"link": link})
1816
1817
        self.napp.handle_link_down(event)
1818
1819
        self.napp.execute_swap_to_failover.assert_called_with(
1820
            default_swap_to_failover
1821
        )
1822 1
1823 1
        self.napp.execute_clear_failover.assert_called_with(
1824 1
            [*default_clear_failover, *swap_to_failover_success]
1825 1
        )
1826 1
1827 1
        self.napp.execute_undeploy.assert_called_with([
1828 1
            *default_undeploy,
1829 1
            *swap_to_failover_failure,
1830 1
            *clear_failover_failure
1831 1
        ])
1832 1
1833 1
        self.napp.mongo_controller.update_evcs.assert_called_with([
1834 1
            evc3.as_dict(),
1835 1
            evc5.as_dict(),
1836 1
            evc1.as_dict(),
1837
            evc4.as_dict(),
1838 1
            evc6.as_dict(),
1839
        ])
1840
1841 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
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
1843
    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
        evc1 = MagicMock(id="1")
1850
        good_path = MagicMock(id="GoodPath")
1851 1
        bad_path = MagicMock(id="BadPath")
1852 1
        evc1.current_path = bad_path
1853
        evc1.failover_path = good_path
1854
        evc2 = MagicMock(id="2")
1855
1856 1
        self.napp.prepare_swap_to_failover_flow = {
1857 1
            evc1: {"1": ["Flow1"]},
1858 1
            evc2: None
1859 1
        }.get
1860 1
1861
        self.napp.prepare_swap_to_failover_event = {
1862 1
            evc1: "FailoverEvent1",
1863
        }.get
1864
1865 1
        success, failure = self.napp.execute_swap_to_failover([evc1, evc2])
1866 1
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
        assert evc1.current_path == good_path
1876
        assert evc1.failover_path == bad_path
1877
1878
        emit_main_mock.assert_called_with(
1879 1
            self.napp.controller,
1880 1
            "failover_link_down",
1881
            content={"1": "FailoverEvent1"}
1882 1
        )
1883 1
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 1
        emit_main_mock: MagicMock,
1890 1
    ):
1891 1
        """Test handle_link_down method when an exception occurs."""
1892 1
        evc1 = MagicMock(id="1")
1893
        good_path = MagicMock(id="GoodPath")
1894
        bad_path = MagicMock(id="BadPath")
1895 1
        evc1.current_path = bad_path
1896
        evc1.failover_path = good_path
1897
        evc2 = MagicMock(id="2")
1898 1
1899 1
        self.napp.prepare_swap_to_failover_flow = {
1900 1
            evc1: {"1": ["Flow1"]},
1901 1
            evc2: None
1902 1
        }.get
1903
1904 1
        self.napp.prepare_swap_to_failover_event = {
1905
            evc1: "FailoverEvent1",
1906 1
        }.get
1907 1
1908 1
        send_flow_mods_mock.side_effect = FlowModException(
1909
            "Flowmod failed to send"
1910
        )
1911 1
1912 1
        success, failure = self.napp.execute_swap_to_failover([evc1, evc2])
1913 1
1914 1
        assert success == []
1915 1
        assert failure == [evc1, evc2]
1916 1
1917 1
        send_flow_mods_mock.assert_called_with(
1918 1
            {"1": ["Flow1"]},
1919
            "install"
1920 1
        )
1921
1922
        assert evc1.current_path == bad_path
1923
        assert evc1.failover_path == good_path
1924 1
1925 1
        emit_main_mock.assert_not_called()
1926 1
1927
    @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 1
        self,
1931
        send_flow_mods_mock: MagicMock,
1932 1
        emit_main_mock: MagicMock,
1933
    ):
1934 1
        """Test execute_clear_failover method."""
1935 1
        evc1 = MagicMock(id="1")
1936 1
        good_path = MagicMock(id="GoodPath")
1937
        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 1
            evc2: None
1945 1
        }.get
1946 1
1947
        self.napp.prepare_clear_failover_event = {
1948 1
            evc1: "FailoverEvent1",
1949 1
        }.get
1950 1
1951
        success, failure = self.napp.execute_clear_failover([evc1, evc2])
1952 1
1953
        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
        assert evc1.current_path == good_path
1962
        assert not evc1.failover_path
1963
1964
        bad_path.make_vlans_available.assert_called_once_with(
1965 1
            self.napp.controller
1966
        )
1967 1
1968 1
        emit_main_mock.assert_called_with(
1969
            self.napp.controller,
1970 1
            "failover_old_path",
1971
            content={"1": "FailoverEvent1"}
1972
        )
1973 1
1974
    @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 1
        send_flow_mods_mock: MagicMock,
1979
        emit_main_mock: MagicMock,
1980
    ):
1981 1
        """Test execute_clear_failover method when an exception occurs."""
1982
        evc1 = MagicMock(id="1")
1983 1
        good_path = MagicMock(id="GoodPath")
1984 1
        bad_path = MagicMock(id="BadPath")
1985
        evc1.current_path = good_path
1986 1
        evc1.failover_path = bad_path
1987
        evc2 = MagicMock(id="2")
1988
1989 1
        self.napp.prepare_clear_failover_flow = {
1990 1
            evc1: {"1": ["Flow1"]},
1991
            evc2: None
1992 1
        }.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
        assert success == []
2005
        assert failure == [evc1, evc2]
2006
2007
        send_flow_mods_mock.assert_called_with(
2008 1
            {"1": ["Flow1"]},
2009
            "delete"
2010
        )
2011
2012
        assert evc1.current_path == good_path
2013
        assert evc1.failover_path == bad_path
2014
2015
        emit_main_mock.assert_not_called()
2016 1
2017 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2018 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2019
    def test_execute_undeploy(
2020
        self,
2021
        send_flow_mods_mock: MagicMock,
2022
        emit_main_mock: MagicMock,
2023
    ):
2024 1
        """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
        evc2 = MagicMock(id="2")
2031 1
2032
        self.napp.prepare_undeploy_flow = {
2033
            evc1: {"1": ["Flow1"]},
2034
            evc2: None
2035
        }.get
2036 1
2037
        success, failure = self.napp.execute_undeploy([evc1, evc2])
2038
2039
        assert success == [evc1]
2040 1
        assert failure == [evc2]
2041
2042 1
        send_flow_mods_mock.assert_called_with(
2043 1
            {"1": ["Flow1"]},
2044
            "delete"
2045 1
        )
2046
2047
        assert not evc1.current_path
2048
        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
        bad_path2.make_vlans_available.assert_called_once_with(
2057
            self.napp.controller
2058
        )
2059 1
2060 1
        evc1.deactivate.assert_called()
2061 1
        evc2.deactivate.assert_not_called()
2062
2063
        emit_main_mock.assert_called_with(
2064
            self.napp.controller,
2065
            "need_redeploy",
2066
            content={"evc_id": "1"}
2067 1
        )
2068 1
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 1
        self,
2073
        send_flow_mods_mock: MagicMock,
2074 1
        emit_main_mock: MagicMock,
2075
    ):
2076
        """Test execute_undeploy method method when an exception occurs."""
2077
        evc1 = MagicMock(id="1")
2078
        bad_path1 = MagicMock(id="GoodPath")
2079 1
        bad_path2 = MagicMock(id="BadPath")
2080
        evc1.current_path = bad_path1
2081
        evc1.failover_path = bad_path2
2082
        evc2 = MagicMock(id="2")
2083 1
2084
        self.napp.prepare_undeploy_flow = {
2085
            evc1: {"1": ["Flow1"]},
2086
            evc2: None
2087 1
        }.get
2088
2089 1
        send_flow_mods_mock.side_effect = FlowModException(
2090 1
            "Flowmod failed to send"
2091
        )
2092 1
2093
        success, failure = self.napp.execute_undeploy([evc1, evc2])
2094
2095
        assert success == []
2096
        assert failure == [evc1, evc2]
2097 1
2098 1
        send_flow_mods_mock.assert_called_with(
2099
            {"1": ["Flow1"]},
2100 1
            "delete"
2101
        )
2102 1
2103 1
        assert evc1.current_path
2104 1
        assert evc1.failover_path
2105
2106
        assert evc2.current_path
2107
        assert evc2.failover_path
2108
2109
        bad_path1.make_vlans_available.assert_not_called()
2110 1
        bad_path2.make_vlans_available.assert_not_called()
2111 1
2112 1
        evc1.deactivate.assert_not_called()
2113 1
        evc2.deactivate.assert_not_called()
2114 1
2115 1
        emit_main_mock.assert_not_called()
2116
2117 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2118
    def test_handle_evc_affected_by_link_down(self, emit_event_mock):
2119
        """Test handle_evc_affected_by_link_down method."""
2120
        uni = create_autospec(UNI)
2121
        evc1 = MagicMock(
2122 1
            id="1",
2123
            metadata="data_mocked",
2124
            _active="true",
2125
            _enabled="false",
2126 1
            uni_a=uni,
2127
            uni_z=uni,
2128 1
        )
2129 1
        evc1.name = "name_mocked"
2130
        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 1
            uni_a=uni,
2137 1
            uni_z=uni,
2138
        )
2139 1
        evc2.name = "mocked_name"
2140
        evc2.handle_link_down.return_value = False
2141
        self.napp.circuits = {"1": evc1, "2": evc2}
2142
2143 1
        event = KytosEvent(name="e1", content={
2144
            "evc_id": "3",
2145
            "link": MagicMock(),
2146
        })
2147
        self.napp.handle_evc_affected_by_link_down(event)
2148
        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 1
                "active": "true",
2158 1
                "enabled": "false",
2159 1
                "uni_a": uni.as_dict(),
2160 1
                "uni_z": uni.as_dict(),
2161 1
            }
2162 1
        )
2163
2164 1
        event.content["evc_id"] = "2"
2165
        self.napp.handle_evc_affected_by_link_down(event)
2166
        emit_event_mock.assert_called_with(
2167
            self.napp.controller, "error_redeploy_link_down", content={
2168
                "evc_id": "2",
2169 1
                "id": "2",
2170
                "name": "mocked_name",
2171
                "metadata": "mocked_data",
2172
                "active": "false",
2173 1
                "enabled": "true",
2174
                "uni_a": uni.as_dict(),
2175
                "uni_z": uni.as_dict(),
2176
            }
2177 1
        )
2178
2179 1
    async def test_add_metadata(self):
2180 1
        """Test method to add metadata"""
2181
        self.napp.controller.loop = asyncio.get_running_loop()
2182 1
        evc_mock = create_autospec(EVC)
2183
        evc_mock.metadata = {}
2184
        evc_mock.id = 1234
2185
        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 1
            json=payload
2191
        )
2192 1
2193 1
        assert response.status_code == 201
2194 1
        evc_mock.extend_metadata.assert_called_with(payload)
2195
2196
    async def test_add_metadata_malformed_json(self):
2197
        """Test method to add metadata with a malformed json"""
2198
        self.napp.controller.loop = asyncio.get_running_loop()
2199
        payload = b'{"metadata1": 1, "metadata2": 2,}'
2200 1
        response = await self.api_client.post(
2201 1
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2202 1
            content=payload,
2203 1
            headers={"Content-Type": "application/json"}
2204 1
        )
2205 1
2206
        assert response.status_code == 400
2207 1
        assert "body contains invalid API" in response.json()["description"]
2208
2209
    async def test_add_metadata_no_body(self):
2210
        """Test method to add metadata with no body"""
2211
        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 1
        )
2215 1
        assert response.status_code == 400
2216
        assert response.json()["description"] == \
2217 1
            "Missing required request body"
2218
2219
    async def test_add_metadata_no_evc(self):
2220
        """Test method to add metadata with no evc"""
2221
        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 1
            json=payload,
2226 1
        )
2227
        assert response.status_code == 404
2228 1
        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
        self.napp.controller.loop = asyncio.get_running_loop()
2234
        payload = {"metadata1": 1, "metadata2": 2}
2235 1
        response = await self.api_client.post(
2236 1
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2237
            data=payload,
2238 1
            headers={"Content-Type": "application/xml"}
2239
        )
2240
        assert response.status_code == 415
2241
        assert "application/xml" in response.json()["description"]
2242
2243
    async def test_get_metadata(self):
2244 1
        """Test method to get metadata"""
2245 1
        evc_mock = create_autospec(EVC)
2246 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2247
        evc_mock.id = 1234
2248
        self.napp.circuits = {"1234": evc_mock}
2249
2250
        response = await self.api_client.get(
2251
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2252 1
        )
2253 1
        assert response.status_code == 200
2254 1
        assert response.json() == {"metadata": evc_mock.metadata}
2255 1
2256 1
    async def test_delete_metadata(self):
2257 1
        """Test method to delete metadata"""
2258
        evc_mock = create_autospec(EVC)
2259 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2260
        evc_mock.id = 1234
2261
        self.napp.circuits = {"1234": evc_mock}
2262
2263
        response = await self.api_client.delete(
2264 1
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2265
        )
2266
        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 1
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2272
        )
2273 1
        assert response.status_code == 404
2274
        assert response.json()["description"] == \
2275
            "circuit_id 1234 not found."
2276
2277
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
2278 1
    def test_load_all_evcs(self, load_evc_mock):
2279 1
        """Test load_evcs method"""
2280
        mock_circuits = {
2281 1
            'circuits': {
2282 1
                1: 'circuit_1',
2283
                2: 'circuit_2',
2284 1
                3: 'circuit_3',
2285 1
                4: 'circuit_4'
2286
            }
2287 1
        }
2288 1
        self.napp.mongo_controller.get_circuits.return_value = mock_circuits
2289
        self.napp.circuits = {2: 'circuit_2', 3: 'circuit_3'}
2290 1
        self.napp.load_all_evcs()
2291
        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
        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
        assert self.napp.controller.buffers.app.put.call_args[1] == timeout_d
2298
2299
    @patch('napps.kytos.mef_eline.main.Main._evc_from_dict')
2300
    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
        evc_from_dict_mock.side_effect = KytosTagError("")
2310
        assert not self.napp._load_evc(evc_dict)
2311
2312
        # case 3: archived evc
2313
        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
        assert not self.napp._load_evc(evc_dict)
2318 1
2319
        # case 4: success creating
2320
        evc.archived = False
2321
        evc.id = 1
2322 1
        self.napp.sched = MagicMock()
2323 1
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
        assert self.napp.circuits[1] == evc
2328
2329
    def test_handle_flow_mod_error(self):
2330
        """Test handle_flow_mod_error method"""
2331
        flow = MagicMock()
2332
        flow.cookie = 0xaa00000000000011
2333
        event = MagicMock()
2334
        event.content = {'flow': flow, 'error_command': 'add'}
2335
        evc = create_autospec(EVC)
2336
        evc.archived = False
2337
        evc.remove_current_flows = MagicMock()
2338
        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
    def test_handle_flow_mod_error_return(self):
2344
        """Test handle_flow_mod_error method with early return."""
2345
        flow = MagicMock()
2346
        flow.cookie = 0xaa00000000000011
2347
        event = MagicMock()
2348
        event.content = {'flow': flow, 'error_command': 'delete'}
2349
2350
        evc = create_autospec(EVC)
2351
        evc.archived = False
2352
        evc.is_enabled.return_value = True
2353
2354 1
        # Flow command is not 'add'
2355
        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 1
2359 1
        # EVC is not enabled
2360 1
        event.content["error_command"] = "add"
2361
        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
        evc.is_enabled.return_value = True
2367
        evc.archived = True
2368 1
        self.napp.handle_flow_mod_error(event)
2369 1
        assert not evc.remove_current_flows.call_count
2370
2371 1
        # EVC does not exist in self.circuits
2372
        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
    @patch("kytos.core.Controller.get_interface_by_id")
2378
    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
        assert not self.napp._uni_from_dict(None)
2383
2384 1
        # case2: invalid interface raises ValueError
2385
        _get_interface_by_id_mock.return_value = None
2386 1
        uni_dict = {
2387 1
            "interface_id": "00:01:1",
2388
            "tag": {"tag_type": 'vlan', "value": 81},
2389
        }
2390
        with pytest.raises(ValueError):
2391
            self.napp._uni_from_dict(uni_dict)
2392
2393
        # case3: success creation
2394 1
        uni_mock = get_uni_mocked(switch_id="00:01")
2395
        _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 1
2399
        # case4: success creation of tag list
2400
        uni_dict["tag"]["value"] = [[1, 10]]
2401
        uni = self.napp._uni_from_dict(uni_dict)
2402
        assert isinstance(uni.user_tag, TAGRange)
2403
2404
        # case5: success creation without tag
2405
        uni_mock.user_tag = None
2406 1
        del uni_dict["tag"]
2407
        uni = self.napp._uni_from_dict(uni_dict)
2408 1
        assert uni == uni_mock
2409 1
2410 1
    def test_handle_flow_delete(self):
2411
        """Test handle_flow_delete method"""
2412
        flow = MagicMock()
2413
        flow.cookie = 0xaa00000000000011
2414
        event = MagicMock()
2415
        event.content = {'flow': flow}
2416
        evc = create_autospec(EVC)
2417
        evc.set_flow_removed_at = MagicMock()
2418 1
        self.napp.circuits = {"00000000000011": evc}
2419
        self.napp.handle_flow_delete(event)
2420 1
        evc.set_flow_removed_at.assert_called_once()
2421 1
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 1
        """Test add_bulk_metadata method"""
2424
        self.napp.controller.loop = asyncio.get_running_loop()
2425 1
        evc_mock = create_autospec(EVC)
2426
        evc_mock.id = 1234
2427
        self.napp.circuits = {"1234": evc_mock}
2428 1
        payload = {
2429 1
            "circuit_ids": ["1234"],
2430
            "metadata1": 1,
2431 1
            "metadata2": 2
2432
        }
2433 1
        response = await self.api_client.post(
2434 1
            f"{self.base_endpoint}/v2/evc/metadata",
2435 1
            json=payload
2436 1
        )
2437
        assert response.status_code == 201
2438 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2439
        ids = payload.pop("circuit_ids")
2440
        assert args[0] == ids
2441 1
        assert args[1] == payload
2442
        assert args[2] == "add"
2443 1
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2444
        assert calls == 1
2445 1
        evc_mock.extend_metadata.assert_called_with(payload)
2446
2447
    async def test_add_bulk_metadata_empty_list(self):
2448
        """Test add_bulk_metadata method empty list"""
2449
        self.napp.controller.loop = asyncio.get_running_loop()
2450
        evc_mock = create_autospec(EVC)
2451
        evc_mock.id = 1234
2452 1
        self.napp.circuits = {"1234": evc_mock}
2453 1
        payload = {
2454
            "circuit_ids": [],
2455 1
            "metadata1": 1,
2456
            "metadata2": 2
2457
        }
2458
        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 1
        assert "invalid" in response.json()["description"]
2464 1
2465 1
    async def test_add_bulk_metadata_no_id(self):
2466 1
        """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 1
            "circuit_ids": ["1234", "4567"]
2473
        }
2474 1
        response = await self.api_client.post(
2475 1
            f"{self.base_endpoint}/v2/evc/metadata",
2476
            json=payload
2477
        )
2478
        assert response.status_code == 404
2479 1
2480 1
    async def test_add_bulk_metadata_no_circuits(self):
2481 1
        """Test add_bulk_metadata without circuit_ids"""
2482
        self.napp.controller.loop = asyncio.get_running_loop()
2483
        evc_mock = create_autospec(EVC)
2484 1
        evc_mock.id = 1234
2485 1
        self.napp.circuits = {"1234": evc_mock}
2486
        payload = {
2487
            "metadata": "data"
2488 1
        }
2489 1
        response = await self.api_client.post(
2490 1
            f"{self.base_endpoint}/v2/evc/metadata",
2491 1
            json=payload
2492 1
        )
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 1
        """Test delete_metadata method"""
2497 1
        self.napp.controller.loop = asyncio.get_running_loop()
2498
        evc_mock = create_autospec(EVC)
2499 1
        evc_mock.id = 1234
2500 1
        self.napp.circuits = {"1234": evc_mock}
2501 1
        payload = {
2502 1
            "circuit_ids": ["1234"]
2503
        }
2504 1
        response = await self.api_client.request(
2505
            "DELETE",
2506 1
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2507 1
            json=payload
2508 1
        )
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
        payload = {"circuit_ids": ["1", "2", "3"]}
2525 1
        response = await self.api_client.request(
2526 1
            "DELETE",
2527 1
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2528
            json=payload
2529
        )
2530 1
        assert response.status_code == 404, response.data
2531 1
        assert response.json()["description"] == ["3"]
2532 1
2533
    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
        self.napp._use_uni_tags(evc_mock)
2540
        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 1
2543 1
        # One UNI tag is not available
2544 1
        evc_mock._use_uni_vlan.side_effect = [KytosTagError(""), None]
2545
        with pytest.raises(KytosTagError):
2546
            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 1
2550 1
        evc_mock._use_uni_vlan.side_effect = [None, KytosTagError("")]
2551
        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
        assert evc_mock.make_uni_vlan_available.call_count == 1
2555
2556
    def test_check_no_tag_duplication(self):
2557 1
        """Test _check_no_tag_duplication"""
2558
        evc = MagicMock()
2559
        evc.check_no_tag_duplicate = MagicMock()
2560 1
        evc.archived = False
2561 1
        evc.id = "1"
2562
        self.napp.circuits = {"1": evc}
2563
        evc_id = "2"
2564
        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
        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
        self.napp._check_no_tag_duplication(evc_id, uni_a, None)
2575 1
        assert evc.check_no_tag_duplicate.call_count == 3
2576 1
2577 1
        self.napp._check_no_tag_duplication(evc_id, None, None)
2578
        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 1
        mock_down,
2586
        mock_up,
2587 1
        mock_time
2588 1
    ):
2589 1
        """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 1
2594 1
        # Created/link_up
2595 1
        name = '.*.switch.interface.created'
2596
        content = {"interface": mock_intf}
2597 1
        event = KytosEvent(name=name, content=content)
2598
        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 1
2602 1
        # Deleted/link_down
2603 1
        name = '.*.switch.interface.deleted'
2604
        event = KytosEvent(name=name, content=content)
2605
        self.napp.handle_on_interface_link_change(event)
2606
        assert mock_down.call_count == 1
2607
        assert mock_up.call_count == 1
2608 1
2609
        # Event delay
2610
        self.napp._intf_events[mock_intf.id]["last_acquired"] = "mock_time"
2611
        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 1
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 1
2621
        # Out of order event
2622 1
        event = KytosEvent(name=name, content=content)
2623
        self.napp._intf_events[mock_intf.id]["event"] = Mock(timestamp=now())
2624 1
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