Test Failed
Pull Request — master (#407)
by Vinicius
15:31 queued 13:18
created

TestMain.test_delete_archived_evc()   B

Complexity

Conditions 1

Size

Total Lines 76
Code Lines 64

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 1

Importance

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