Passed
Pull Request — master (#407)
by Vinicius
09:10 queued 05:00
created

TestMain.test_update_circuit_invalid_path()   B

Complexity

Conditions 1

Size

Total Lines 82
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 40
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 67
nop 12
dl 0
loc 82
ccs 40
cts 40
cp 1
crap 1
rs 8.08
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 1
from napps.kytos.mef_eline.tests.helpers import get_uni_mocked
14
15
16 1
async def test_on_table_enabled():
17
    """Test on_table_enabled"""
18
    # 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 1
    napp = Main(controller)
24
25
    # Succesfully setting table groups
26 1
    content = {"mef_eline": {"epl": 2}}
27 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
28
                       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 1
    assert controller.buffers.app.aput.call_count == 1
33
34
    # Failure at setting table groups
35 1
    content = {"mef_eline": {"unknown": 123}}
36 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
37
                       content=content)
38 1
    await napp.on_table_enabled(event)
39 1
    assert controller.buffers.app.aput.call_count == 1
40
41
    # Failure with early return
42 1
    content = {}
43 1
    event = KytosEvent(name="kytos/of_multi_table.enable_table",
44
                       content=content)
45 1
    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 1
class TestMain:
52
    """Test the Main class."""
53
54 1
    def setup_method(self):
55
        """Execute steps before each tests.
56
57
        Set the server_name_url_url from kytos/mef_eline
58
        """
59
60
        # The decorator run_on_thread is patched, so methods that listen
61
        # for events do not run on threads while tested.
62
        # Decorators have to be patched before the methods that are
63
        # decorated with them are imported.
64 1
        patch("kytos.core.helpers.run_on_thread", lambda x: x).start()
65
        # pylint: disable=import-outside-toplevel
66 1
        from napps.kytos.mef_eline.main import Main
67 1
        Main.get_eline_controller = MagicMock()
68 1
        controller = get_controller_mock()
69 1
        self.napp = Main(controller)
70 1
        self.api_client = get_test_client(controller, self.napp)
71 1
        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
            "kytos/core.shutdown",
77
            "kytos/core.shutdown.kytos/mef_eline",
78
            "kytos/topology.link_up",
79
            "kytos/topology.link_down",
80
        ]
81 1
        actual_events = self.napp.listeners()
82
83 1
        for _event in expected_events:
84 1
            assert _event in actual_events, _event
85
86 1
    @patch('napps.kytos.mef_eline.main.log')
87 1
    @patch('napps.kytos.mef_eline.main.Main.execute_consistency')
88 1
    def test_execute(self, mock_execute_consistency, mock_log):
89
        """Test execute."""
90 1
        self.napp.execution_rounds = 0
91 1
        self.napp.execute()
92 1
        mock_execute_consistency.assert_called()
93 1
        assert mock_log.debug.call_count == 2
94
95
        # Test locked should return
96 1
        mock_execute_consistency.call_count = 0
97 1
        mock_log.info.call_count = 0
98
        # pylint: disable=protected-access
99 1
        self.napp._lock = MagicMock()
100 1
        self.napp._lock.locked.return_value = True
101
        # pylint: enable=protected-access
102 1
        self.napp.execute()
103 1
        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 1
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
108 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
109 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_list_traces")
110 1
    def test_execute_consistency(self, mock_check_list_traces, *args):
111
        """Test execute_consistency."""
112 1
        (mongo_controller_upsert_mock, mock_load_evc, mock_settings) = args
113
114 1
        stored_circuits = {'1': {'name': 'circuit_1'},
115
                           '2': {'name': 'circuit_2'},
116
                           '3': {'name': 'circuit_3'}}
117 1
        mongo_controller_upsert_mock.return_value = True
118 1
        self.napp.mongo_controller.get_circuits.return_value = {
119
            "circuits": stored_circuits
120
        }
121
122 1
        mock_settings.WAIT_FOR_OLD_PATH = -1
123 1
        evc1 = MagicMock(id=1, service_level=0, creation_time=1)
124 1
        evc1.is_enabled.return_value = True
125 1
        evc1.is_active.return_value = False
126 1
        evc1.lock.locked.return_value = False
127 1
        evc1.has_recent_removed_flow.return_value = False
128 1
        evc1.is_recent_updated.return_value = False
129 1
        evc1.execution_rounds = 0
130 1
        evc2 = MagicMock(id=2, service_level=7, creation_time=1)
131 1
        evc2.is_enabled.return_value = True
132 1
        evc2.is_active.return_value = False
133 1
        evc2.lock.locked.return_value = False
134 1
        evc2.has_recent_removed_flow.return_value = False
135 1
        evc2.is_recent_updated.return_value = False
136 1
        evc2.execution_rounds = 0
137 1
        self.napp.circuits = {'1': evc1, '2': evc2}
138 1
        assert self.napp.get_evcs_by_svc_level() == [evc2, evc1]
139
140 1
        mock_check_list_traces.return_value = {
141
                                                1: True,
142
                                                2: False
143
                                            }
144
145 1
        self.napp.execute_consistency()
146 1
        assert evc1.activate.call_count == 1
147 1
        assert evc1.sync.call_count == 1
148 1
        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 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_list_traces")
155 1
    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
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
            "circuits": stored_circuits
163
        }
164
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 1
        evc1.lock.locked.return_value = False
170 1
        evc1.has_recent_removed_flow.return_value = False
171 1
        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 1
        mock_settings.WAIT_FOR_OLD_PATH = 1
177
178 1
        mock_check_list_traces.return_value = {1: False}
179
180 1
        self.napp.execute_consistency()
181 1
        assert evc1.deploy.call_count == 0
182 1
        self.napp.execute_consistency()
183 1
        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 1
        _validate_mock.return_value = True
194 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
195 1
        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
                "tag": {"tag_type": 'vlan', "value": 1},
204
            },
205
            "circuit_scheduler": [
206
                {"frequency": "* * * * *", "action": "create"}
207
            ],
208
            "queue_id": 5,
209
        }
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 1
        assert evc_response.circuit_scheduler is not None
216 1
        assert evc_response.name is not None
217 1
        assert evc_response.queue_id is not None
218
219 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
220 1
    @patch("napps.kytos.mef_eline.models.evc.EVCBase._validate")
221 1
    @patch("kytos.core.Controller.get_interface_by_id")
222 1
    def test_evc_from_dict_paths(
223
        self, _get_interface_by_id_mock, _validate_mock, uni_from_dict_mock
224
    ):
225
        """
226
        Test the helper method that create an EVN from dict.
227
228
        Verify object creation with circuit data and schedule data.
229
        """
230
231 1
        _get_interface_by_id_mock.return_value = get_uni_mocked().interface
232 1
        _validate_mock.return_value = True
233 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
234 1
        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
                        "interface_id": "00:00:00:00:00:00:00:02:2"
252
                    },
253
                }
254
            ],
255
            "backup_path": [],
256
        }
257
258
        # pylint: disable=protected-access
259 1
        evc_response = self.napp._evc_from_dict(payload)
260 1
        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 1
        assert len(evc_response.current_path) == 0
266 1
        assert len(evc_response.backup_path) == 0
267 1
        assert len(evc_response.primary_path) == 1
268
269 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
270 1
    @patch("napps.kytos.mef_eline.models.evc.EVCBase._validate")
271 1
    @patch("kytos.core.Controller.get_interface_by_id")
272 1
    def test_evc_from_dict_links(
273
        self, _get_interface_by_id_mock, _validate_mock, uni_from_dict_mock
274
    ):
275
        """
276
        Test the helper method that create an EVN from dict.
277
278
        Verify object creation with circuit data and schedule data.
279
        """
280 1
        _get_interface_by_id_mock.return_value = get_uni_mocked().interface
281 1
        _validate_mock.return_value = True
282 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
283 1
        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
                        }
306
                    },
307
                }
308
            ],
309
            "backup_links": [],
310
        }
311
312
        # pylint: disable=protected-access
313 1
        evc_response = self.napp._evc_from_dict(payload)
314 1
        assert evc_response is not None
315 1
        assert evc_response.uni_a is not None
316 1
        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
323 1
    async def test_list_without_circuits(self):
324
        """Test if list circuits return 'no circuit stored.'."""
325 1
        circuits = {"circuits": {}}
326 1
        self.napp.mongo_controller.get_circuits.return_value = circuits
327 1
        url = f"{self.base_endpoint}/v2/evc/"
328 1
        response = await self.api_client.get(url)
329 1
        assert response.status_code == 200, response.data
330 1
        assert not response.json()
331
332 1
    async def test_list_no_circuits_stored(self):
333
        """Test if list circuits return all circuits stored."""
334 1
        circuits = {"circuits": {}}
335 1
        self.napp.mongo_controller.get_circuits.return_value = circuits
336
337 1
        url = f"{self.base_endpoint}/v2/evc/"
338 1
        response = await self.api_client.get(url)
339 1
        expected_result = circuits["circuits"]
340 1
        assert response.json() == expected_result
341
342 1 View Code Duplication
    async def test_list_with_circuits_stored(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
343
        """Test if list circuits return all circuits stored."""
344 1
        circuits = {
345
            'circuits':
346
            {"1": {"name": "circuit_1"}, "2": {"name": "circuit_2"}}
347
        }
348 1
        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 1
        response = await self.api_client.get(url)
353 1
        expected_result = circuits["circuits"]
354 1
        get_circuits.assert_called_with(archived="false", metadata={})
355 1
        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
        """Test if list circuits only archived circuits."""
359 1
        circuits = {
360
            'circuits':
361
            {
362
                "1": {"name": "circuit_1", "archived": True},
363
            }
364
        }
365 1
        get_circuits = self.napp.mongo_controller.get_circuits
366 1
        get_circuits.return_value = circuits
367
368 1
        url = f"{self.base_endpoint}/v2/evc/?archived=true&metadata.a=1"
369 1
        response = await self.api_client.get(url)
370 1
        get_circuits.assert_called_with(archived="true",
371
                                        metadata={"metadata.a": "1"})
372 1
        expected_result = {"1": circuits["circuits"]["1"]}
373 1
        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
            'circuits': {
379
                "1": {"name": "circuit_1"},
380
                "2": {"name": "circuit_2", "archived": True},
381
            }
382
        }
383 1
        self.napp.mongo_controller.get_circuits.return_value = circuits
384
385 1
        url = f"{self.base_endpoint}/v2/evc/?archived=null"
386 1
        response = await self.api_client.get(url)
387 1
        expected_result = circuits["circuits"]
388 1
        assert response.json() == expected_result
389
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 1
        self.napp.mongo_controller.get_circuit.return_value = circuit
394
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
        """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
408 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
409 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
410 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
411 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
412 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
413 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
414 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
415 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
416 1
    async def test_create_a_circuit_case_1(
417
        self,
418
        validate_mock,
419
        evc_as_dict_mock,
420
        mongo_controller_upsert_mock,
421
        uni_from_dict_mock,
422
        sched_add_mock,
423
        evc_deploy_mock,
424
        mock_use_uni_tags,
425
        mock_tags_equal,
426
        event_loop
427
    ):
428
        """Test create a new circuit."""
429
        # 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 1
        mock_tags_equal.return_value = True
436 1
        uni1 = create_autospec(UNI)
437 1
        uni2 = create_autospec(UNI)
438 1
        uni1.interface = create_autospec(Interface)
439 1
        uni2.interface = create_autospec(Interface)
440 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
441 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
442 1
        uni_from_dict_mock.side_effect = [uni1, uni2]
443 1
        evc_as_dict_mock.return_value = {}
444 1
        sched_add_mock.return_value = True
445 1
        self.napp.mongo_controller.get_circuits.return_value = {}
446
447 1
        url = f"{self.base_endpoint}/v2/evc/"
448 1
        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
                    "ownership": "red"
464
                }
465
            },
466
            "secondary_constraints": {
467
                "spf_attribute": "priority",
468
                "mandatory_metrics": {
469
                    "ownership": "blue"
470
                }
471
            }
472
        }
473
474 1
        response = await self.api_client.post(url, json=payload)
475 1
        current_data = response.json()
476
477
        # verify expected result from request
478 1
        assert 201 == response.status_code
479 1
        assert "circuit_id" in current_data
480
481
        # verify uni called
482 1
        uni_from_dict_mock.called_twice()
483 1
        uni_from_dict_mock.assert_any_call(payload["uni_z"])
484 1
        uni_from_dict_mock.assert_any_call(payload["uni_a"])
485
486
        # verify validation called
487 1
        validate_mock.assert_called_once()
488 1
        validate_mock.assert_called_with(
489
            table_group={'evpl': 0, 'epl': 0},
490
            frequency="* * * * *",
491
            name="my evc1",
492
            uni_a=uni1,
493
            uni_z=uni2,
494
            dynamic_backup_path=True,
495
            primary_constraints=payload["primary_constraints"],
496
            secondary_constraints=payload["secondary_constraints"],
497
        )
498
        # verify save method is called
499 1
        mongo_controller_upsert_mock.assert_called_once()
500
501
        # verify evc as dict is called to save in the box
502 1
        evc_as_dict_mock.assert_called()
503
        # verify add circuit in sched
504 1
        sched_add_mock.assert_called_once()
505
506 1
    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 1
        current_data = response.json()
513 1
        assert 400 == response.status_code
514 1
        assert "Missing required request body" in current_data["description"]
515
516 1
    async def test_create_a_circuit_case_3(self, event_loop):
517
        """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
522 1
        response = await self.api_client.post(
523
            url,
524
            json="This is an {Invalid:} JSON",
525
        )
526 1
        current_data = response.json()
527 1
        assert 400 == response.status_code
528 1
        assert "contains invalid" in current_data["description"]
529
530 1
    @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
        self,
534
        mongo_controller_upsert_mock,
535
        uni_from_dict_mock,
536
        event_loop
537
    ):
538
        """Test create a new circuit trying to send request with an
539
        invalid value."""
540 1
        self.napp.controller.loop = event_loop
541
        # pylint: disable=too-many-locals
542 1
        uni_from_dict_mock.side_effect = ValueError("Could not instantiate")
543 1
        mongo_controller_upsert_mock.return_value = True
544 1
        url = f"{self.base_endpoint}/v2/evc/"
545
546 1
        payload = {
547
            "name": "my evc1",
548
            "frequency": "* * * * *",
549
            "uni_a": {
550
                "interface_id": "00:00:00:00:00:00:00:01:76",
551
                "tag": {"tag_type": 'vlan', "value": 80},
552
            },
553
            "uni_z": {
554
                "interface_id": "00:00:00:00:00:00:00:02:2",
555
                "tag": {"tag_type": 'vlan', "value": 1},
556
            },
557
        }
558
559 1
        response = await self.api_client.post(url, json=payload)
560 1
        current_data = response.json()
561 1
        expected_data = "Error creating UNI: Invalid value"
562 1
        assert 400 == response.status_code
563 1
        assert current_data["description"] == expected_data
564
565 1
        payload["name"] = 1
566 1
        response = await self.api_client.post(url, json=payload)
567 1
        assert 400 == response.status_code, response.data
568
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
        self,
573
        validate_mock,
574
        uni_from_dict_mock,
575
        event_loop
576
    ):
577
        """Test create a new intra circuit with a disabled switch"""
578 1
        self.napp.controller.loop = event_loop
579 1
        validate_mock.return_value = True
580 1
        uni1 = create_autospec(UNI)
581 1
        uni1.interface = create_autospec(Interface)
582 1
        uni1.interface.switch = MagicMock()
583 1
        uni1.interface.switch.return_value = "00:00:00:00:00:00:00:01"
584 1
        uni1.interface.switch.status = EntityStatus.DISABLED
585 1
        uni_from_dict_mock.side_effect = [uni1, uni1]
586 1
        url = f"{self.base_endpoint}/v2/evc/"
587 1
        payload = {
588
            "name": "my evc1",
589
            "dynamic_backup_path": True,
590
            "uni_a": {
591
                "interface_id": "00:00:00:00:00:00:00:01:1",
592
                "tag": {"tag_type": 'vlan', "value": 80},
593
            },
594
            "uni_z": {
595
                "interface_id": "00:00:00:00:00:00:00:01:2",
596
                "tag": {"tag_type": 'vlan', "value": 1},
597
            },
598
        }
599
600 1
        response = await self.api_client.post(url, json=payload)
601 1
        assert 409 == response.status_code, response.data
602
603 1
    async def test_create_a_circuit_invalid_queue_id(self, event_loop):
604
        """Test create a new circuit with invalid queue_id."""
605 1
        self.napp.controller.loop = event_loop
606 1
        url = f"{self.base_endpoint}/v2/evc/"
607
608 1
        payload = {
609
            "name": "my evc1",
610
            "queue_id": 8,
611
            "uni_a": {
612
                "interface_id": "00:00:00:00:00:00:00:01:76",
613
                "tag": {"tag_type": 'vlan', "value": 80},
614
            },
615
            "uni_z": {
616
                "interface_id": "00:00:00:00:00:00:00:02:2",
617
                "tag": {"tag_type": 'vlan', "value": 1},
618
            },
619
        }
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
624 1
        assert response.status_code == 400
625 1
        assert expected_data in current_data["description"]
626
627 1 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 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
629 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
630 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
631 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
632 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
633 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
634 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
635 1
    async def test_create_circuit_already_enabled(
636
        self,
637
        evc_as_dict_mock,
638
        validate_mock,
639
        mongo_controller_upsert_mock,
640
        uni_from_dict_mock,
641
        sched_add_mock,
642
        evc_deploy_mock,
643
        mock_use_uni_tags,
644
        mock_tags_equal,
645
        event_loop
646
    ):
647
        """Test create an already created circuit."""
648
        # pylint: disable=too-many-locals
649 1
        self.napp.controller.loop = event_loop
650 1
        validate_mock.return_value = True
651 1
        mongo_controller_upsert_mock.return_value = True
652 1
        sched_add_mock.return_value = True
653 1
        evc_deploy_mock.return_value = True
654 1
        mock_use_uni_tags.return_value = True
655 1
        mock_tags_equal.return_value = True
656 1
        uni1 = create_autospec(UNI)
657 1
        uni2 = create_autospec(UNI)
658 1
        uni1.interface = create_autospec(Interface)
659 1
        uni2.interface = create_autospec(Interface)
660 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
661 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
662 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
663
664 1
        payload = {
665
            "name": "my evc1",
666
            "uni_a": {
667
                "interface_id": "00:00:00:00:00:00:00:01:1",
668
                "tag": {"tag_type": 'vlan', "value": 80},
669
            },
670
            "uni_z": {
671
                "interface_id": "00:00:00:00:00:00:00:02:2",
672
                "tag": {"tag_type": 'vlan', "value": 1},
673
            },
674
            "dynamic_backup_path": True,
675
        }
676
677 1
        evc_as_dict_mock.return_value = payload
678 1
        response = await self.api_client.post(
679
            f"{self.base_endpoint}/v2/evc/",
680
            json=payload
681
        )
682 1
        assert 201 == response.status_code
683
684 1
        response = await self.api_client.post(
685
            f"{self.base_endpoint}/v2/evc/",
686
            json=payload
687
        )
688 1
        current_data = response.json()
689 1
        expected_data = "The EVC already exists."
690 1
        assert current_data["description"] == expected_data
691 1
        assert 409 == response.status_code
692
693 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
694 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
695 1
    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 1
        self.napp.controller.loop = event_loop
703 1
        mock_tags_equal.return_value = True
704 1
        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 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
712
713 1
        payload = {
714
            "name": "my evc1",
715
            "frequency": "* * * * *",
716
            "uni_a": {
717
                "interface_id": "00:00:00:00:00:00:00:01:1",
718
                "tag": {"tag_type": 'vlan', "value": 80},
719
            },
720
            "uni_z": {
721
                "interface_id": "00:00:00:00:00:00:00:02:2",
722
                "tag": {"tag_type": 'vlan', "value": 1},
723
            },
724
        }
725
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 1
        expected_data += "or allow dynamic paths."
730 1
        assert 400 == response.status_code, response.data
731 1
        assert current_data["description"] == expected_data
732
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
        """Test create_circuit with KytosTagError"""
736 1
        self.napp.controller.loop = event_loop
737 1
        url = f"{self.base_endpoint}/v2/evc/"
738 1
        mock_evc.side_effect = KytosTagError("")
739 1
        payload = {
740
            "name": "my evc1",
741
            "uni_a": {
742
                "interface_id": "00:00:00:00:00:00:00:01:1",
743
            },
744
            "uni_z": {
745
                "interface_id": "00:00:00:00:00:00:00:02:2",
746
            },
747
        }
748 1
        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 1
    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 1
        self.napp.controller.loop = event_loop
761 1
        mock_check_disabled_component.return_value = True
762 1
        url = f"{self.base_endpoint}/v2/evc/"
763 1
        uni1 = get_uni_mocked()
764 1
        uni2 = get_uni_mocked()
765 1
        evc = MagicMock(uni_a=uni1, uni_z=uni2)
766 1
        evc.primary_path = MagicMock()
767 1
        evc.backup_path = MagicMock()
768
769
        # Backup_path invalid
770 1
        evc.backup_path.is_valid = MagicMock(side_effect=InvalidPath)
771 1
        mock_evc.return_value = evc
772 1
        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 1
        response = await self.api_client.post(url, json=payload)
782 1
        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 1
        response = await self.api_client.post(url, json=payload)
789 1
        assert response.status_code == 400, response.data
790
791 1
    @patch("napps.kytos.mef_eline.main.Main._is_duplicated_evc")
792 1
    @patch("napps.kytos.mef_eline.main.check_disabled_component")
793 1
    @patch("napps.kytos.mef_eline.main.Main._evc_from_dict")
794 1
    async def test_create_circuit_case_8(
795
        self,
796
        mock_evc,
797
        mock_check_disabled_component,
798
        mock_duplicated,
799
        event_loop
800
    ):
801
        """Test create_circuit wit no equal tag lists"""
802 1
        self.napp.controller.loop = event_loop
803 1
        mock_check_disabled_component.return_value = True
804 1
        mock_duplicated.return_value = False
805 1
        url = f"{self.base_endpoint}/v2/evc/"
806 1
        uni1 = get_uni_mocked()
807 1
        uni2 = get_uni_mocked()
808 1
        evc = MagicMock(uni_a=uni1, uni_z=uni2)
809 1
        evc._tag_lists_equal = MagicMock(return_value=False)
810 1
        mock_evc.return_value = evc
811 1
        payload = {
812
            "name": "my evc1",
813
            "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 1
        response = await self.api_client.post(url, json=payload)
823 1
        assert response.status_code == 400, response.data
824
825 1
    async def test_redeploy_evc(self):
826
        """Test endpoint to redeploy an EVC."""
827 1
        evc1 = MagicMock()
828 1
        evc1.is_enabled.return_value = True
829 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
830 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
831 1
        response = await self.api_client.patch(url)
832 1
        assert response.status_code == 202, response.data
833
834 1
    async def test_redeploy_evc_disabled(self):
835
        """Test endpoint to redeploy an EVC."""
836 1
        evc1 = MagicMock()
837 1
        evc1.is_enabled.return_value = False
838 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
839 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
840 1
        response = await self.api_client.patch(url)
841 1
        assert response.status_code == 409, response.data
842
843 1
    async def test_redeploy_evc_deleted(self):
844
        """Test endpoint to redeploy an EVC."""
845 1
        evc1 = MagicMock()
846 1
        evc1.is_enabled.return_value = True
847 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
848 1
        url = f"{self.base_endpoint}/v2/evc/3/redeploy"
849 1
        response = await self.api_client.patch(url)
850 1
        assert response.status_code == 404, response.data
851
852 1
    async def test_list_schedules__no_data_stored(self):
853
        """Test if list circuits return all circuits stored."""
854 1
        self.napp.mongo_controller.get_circuits.return_value = {"circuits": {}}
855
856 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
857
858 1
        response = await self.api_client.get(url)
859 1
        assert response.status_code == 200
860 1
        assert not response.json()
861
862 1
    def _add_mongodb_schedule_data(self, data_mock):
863
        """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
            "uni_a": {
869
                "interface_id": "00:00:00:00:00:00:00:01:1",
870
                "tag": {"tag_type": 'vlan', "value": 80},
871
            },
872
            "uni_z": {
873
                "interface_id": "00:00:00:00:00:00:00:02:2",
874
                "tag": {"tag_type": 'vlan', "value": 1},
875
            },
876
            "circuit_scheduler": [
877
                {"id": "1", "frequency": "* * * * *", "action": "create"},
878
                {"id": "2", "frequency": "1 * * * *", "action": "remove"},
879
            ],
880
        }
881 1
        circuits["circuits"].update({"aa:aa:aa": payload_1})
882 1
        payload_2 = {
883
            "id": "bb:bb:bb",
884
            "name": "my second evc2",
885
            "uni_a": {
886
                "interface_id": "00:00:00:00:00:00:00:01:2",
887
                "tag": {"tag_type": 'vlan', "value": 90},
888
            },
889
            "uni_z": {
890
                "interface_id": "00:00:00:00:00:00:00:03:2",
891
                "tag": {"tag_type": 'vlan', "value": 100},
892
            },
893
            "circuit_scheduler": [
894
                {"id": "3", "frequency": "1 * * * *", "action": "create"},
895
                {"id": "4", "frequency": "2 * * * *", "action": "remove"},
896
            ],
897
        }
898 1
        circuits["circuits"].update({"bb:bb:bb": payload_2})
899 1
        payload_3 = {
900
            "id": "cc:cc:cc",
901
            "name": "my third evc3",
902
            "uni_a": {
903
                "interface_id": "00:00:00:00:00:00:00:03:1",
904
                "tag": {"tag_type": 'vlan', "value": 90},
905
            },
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 1
        circuits["circuits"].update({"cc:cc:cc": payload_3})
912
        # Add one circuit to the mongodb.
913 1
        data_mock.return_value = circuits
914
915 1
    async def test_list_schedules_from_mongodb(self):
916
        """Test if list circuits return specific circuits stored."""
917 1
        self._add_mongodb_schedule_data(
918
            self.napp.mongo_controller.get_circuits
919
        )
920
921 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
922
923
        # Call URL
924 1
        response = await self.api_client.get(url)
925
        # Expected JSON data from response
926 1
        expected = [
927
            {
928
                "circuit_id": "aa:aa:aa",
929
                "schedule": {
930
                    "action": "create",
931
                    "frequency": "* * * * *",
932
                    "id": "1",
933
                },
934
                "schedule_id": "1",
935
            },
936
            {
937
                "circuit_id": "aa:aa:aa",
938
                "schedule": {
939
                    "action": "remove",
940
                    "frequency": "1 * * * *",
941
                    "id": "2",
942
                },
943
                "schedule_id": "2",
944
            },
945
            {
946
                "circuit_id": "bb:bb:bb",
947
                "schedule": {
948
                    "action": "create",
949
                    "frequency": "1 * * * *",
950
                    "id": "3",
951
                },
952
                "schedule_id": "3",
953
            },
954
            {
955
                "circuit_id": "bb:bb:bb",
956
                "schedule": {
957
                    "action": "remove",
958
                    "frequency": "2 * * * *",
959
                    "id": "4",
960
                },
961
                "schedule_id": "4",
962
            },
963
        ]
964
965 1
        assert response.status_code == 200
966 1
        assert expected == response.json()
967
968 1
    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 1
        requested_circuit_id = "bb:bb:bb"
975 1
        evc = self.napp.mongo_controller.get_circuits()
976 1
        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
983
        # Expected JSON data from response
984 1
        expected = [
985
            {"action": "create", "frequency": "1 * * * *", "id": "3"},
986
            {"action": "remove", "frequency": "2 * * * *", "id": "4"},
987
        ]
988
989 1
        assert response.status_code == 200
990 1
        assert expected == response.json()["circuit_scheduler"]
991
992 1
    async def test_get_specific_schedules_from_mongodb_not_found(self):
993
        """Test get specific schedule ID that does not exist."""
994 1
        requested_id = "blah"
995 1
        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
1001 1
        expected = "circuit_id blah not found"
1002
        # Assert response not found
1003 1
        assert response.status_code == 404
1004 1
        assert expected == response.json()["description"]
1005
1006 1
    def _uni_from_dict_side_effect(self, uni_dict):
1007 1
        interface_id = uni_dict.get("interface_id")
1008 1
        tag_dict = uni_dict.get("tag")
1009 1
        interface = Interface(interface_id, "0", MagicMock(id="1"))
1010 1
        return UNI(interface, tag_dict)
1011
1012 1
    @patch("apscheduler.schedulers.background.BackgroundScheduler.add_job")
1013 1
    @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 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1017 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1018 1
    async def test_create_schedule(
1019
        self,
1020
        validate_mock,
1021
        evc_as_dict_mock,
1022
        mongo_controller_upsert_mock,
1023
        uni_from_dict_mock,
1024
        sched_add_mock,
1025
        scheduler_add_job_mock,
1026
        event_loop
1027
    ):
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
1036 1
        self._add_mongodb_schedule_data(
1037
            self.napp.mongo_controller.get_circuits
1038
        )
1039
1040 1
        requested_id = "bb:bb:bb"
1041 1
        url = f"{self.base_endpoint}/v2/evc/schedule/"
1042
1043 1
        payload = {
1044
            "circuit_id": requested_id,
1045
            "schedule": {"frequency": "1 * * * *", "action": "create"},
1046
            "metadata": {"metadata1": "test_data"},
1047
        }
1048
1049
        # Call URL
1050 1
        response = await self.api_client.post(url, json=payload)
1051 1
        response_json = response.json()
1052
1053 1
        assert response.status_code == 201
1054 1
        scheduler_add_job_mock.assert_called_once()
1055 1
        mongo_controller_upsert_mock.assert_called_once()
1056 1
        assert payload["schedule"]["frequency"] == response_json["frequency"]
1057 1
        assert payload["schedule"]["action"] == response_json["action"]
1058 1
        assert response_json["id"] is not None
1059
1060
        # Case 2: there is no schedule
1061 1
        payload = {
1062
              "circuit_id": "cc:cc:cc",
1063
              "schedule": {
1064
                "frequency": "1 * * * *",
1065
                "action": "create"
1066
              }
1067
            }
1068 1
        response = await self.api_client.post(url, json=payload)
1069 1
        assert response.status_code == 201
1070
1071 1
    async def test_create_schedule_invalid_request(self, event_loop):
1072
        """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
1078
        # case 1: empty post
1079 1
        response = await self.api_client.post(url, json={})
1080 1
        assert response.status_code == 400
1081
1082
        # case 2: content-type not specified
1083 1
        payload = {
1084
            "circuit_id": "bb:bb:bb",
1085
            "schedule": {
1086
                "frequency": "1 * * * *",
1087
                "action": "create"
1088
            }
1089
        }
1090 1
        response = await self.api_client.post(url, json=payload)
1091 1
        assert response.status_code == 409
1092
1093
        # case 3: not a dictionary
1094 1
        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 1
        payload = {
1100
            "schedule": {
1101
                "frequency": "1 * * * *",
1102
                "action": "create"
1103
            }
1104
        }
1105 1
        response = await self.api_client.post(url, json=payload)
1106 1
        assert response.status_code == 400
1107
1108
        # case 5: missing schedule
1109 1
        payload = {
1110
            "circuit_id": "bb:bb:bb"
1111
        }
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 1
        payload = {
1117
            "circuit_id": "xx:xx:xx",
1118
            "schedule": {
1119
                "frequency": "1 * * * *",
1120
                "action": "create"
1121
            }
1122
        }
1123 1
        response = await self.api_client.post(url, json=payload)
1124 1
        assert response.status_code == 404
1125
1126
        # case 7: archived or deleted evc
1127 1
        evc1.archived.return_value = True
1128 1
        payload = {
1129
            "circuit_id": "bb:bb:bb",
1130
            "schedule": {
1131
                "frequency": "1 * * * *",
1132
                "action": "create"
1133
            }
1134
        }
1135 1
        response = await self.api_client.post(url, json=payload)
1136 1
        assert response.status_code == 409
1137
1138
        # case 8: invalid json
1139 1
        response = await self.api_client.post(url, json="test")
1140 1
        assert response.status_code == 400
1141
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 1
    @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 1
    async def test_update_schedule(
1149
        self,
1150
        validate_mock,
1151
        evc_as_dict_mock,
1152
        mongo_controller_upsert_mock,
1153
        uni_from_dict_mock,
1154
        sched_add_mock,
1155
        scheduler_remove_job_mock,
1156
        event_loop
1157
    ):
1158
        """Test create a circuit schedule."""
1159 1
        self.napp.controller.loop = event_loop
1160 1
        mongo_payload_1 = {
1161
            "circuits": {
1162
                "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
                        "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 1
        validate_mock.return_value = True
1185 1
        mongo_controller_upsert_mock.return_value = True
1186 1
        sched_add_mock.return_value = True
1187 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1188 1
        evc_as_dict_mock.return_value = {}
1189 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1190 1
        scheduler_remove_job_mock.return_value = True
1191
1192 1
        requested_schedule_id = "1"
1193 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1194
1195 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1196
1197
        # Call URL
1198 1
        response = await self.api_client.patch(url, json=payload)
1199 1
        response_json = response.json()
1200
1201 1
        assert response.status_code == 200
1202 1
        scheduler_remove_job_mock.assert_called_once()
1203 1
        mongo_controller_upsert_mock.assert_called_once()
1204 1
        assert payload["frequency"] == response_json["frequency"]
1205 1
        assert payload["action"] == response_json["action"]
1206 1
        assert response_json["id"] is not None
1207
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
    ):
1212
        """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 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1216
1217 1
        find_evc_by_schedule_id_mock.return_value = None, None
1218
1219 1
        response = await self.api_client.patch(url, json=payload)
1220 1
        assert response.status_code == 404
1221
1222 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1223 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1224 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1225 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1226 1
    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 1
        self.napp.controller.loop = event_loop
1236 1
        mongo_payload_1 = {
1237
            "circuits": {
1238
                "aa:aa:aa": {
1239
                    "id": "aa:aa:aa",
1240
                    "name": "my evc1",
1241
                    "archived": True,
1242
                    "circuit_scheduler": [
1243
                        {
1244
                            "id": "1",
1245
                            "frequency": "* * * * *",
1246
                            "action": "create"
1247
                        }
1248
                    ],
1249
                }
1250
            }
1251
        }
1252
1253 1
        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 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1261
1262 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1263
1264
        # Call URL
1265 1
        response = await self.api_client.patch(url, json=payload)
1266 1
        assert response.status_code == 409
1267
1268 1
    @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 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1272 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1273 1
    async def test_delete_schedule(self, *args):
1274
        """Test create a circuit schedule."""
1275 1
        (
1276
            validate_mock,
1277
            evc_as_dict_mock,
1278
            mongo_controller_upsert_mock,
1279
            uni_from_dict_mock,
1280
            scheduler_remove_job_mock,
1281
        ) = args
1282
1283 1
        mongo_payload_1 = {
1284
            "circuits": {
1285
                "2": {
1286
                    "id": "2",
1287
                    "name": "my evc1",
1288
                    "uni_a": {
1289
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1290
                        "tag": {"tag_type": 'vlan', "value": 80},
1291
                    },
1292
                    "uni_z": {
1293
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1294
                        "tag": {"tag_type": 'vlan', "value": 1},
1295
                    },
1296
                    "circuit_scheduler": [
1297
                        {
1298
                            "id": "1",
1299
                            "frequency": "* * * * *",
1300
                            "action": "create"
1301
                        }
1302
                    ],
1303
                }
1304
            }
1305
        }
1306 1
        validate_mock.return_value = True
1307 1
        mongo_controller_upsert_mock.return_value = True
1308 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1309 1
        evc_as_dict_mock.return_value = {}
1310 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1311 1
        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
1316
        # Call URL
1317 1
        response = await self.api_client.delete(url)
1318
1319 1
        assert response.status_code == 200
1320 1
        scheduler_remove_job_mock.assert_called_once()
1321 1
        mongo_controller_upsert_mock.assert_called_once()
1322 1
        assert "Schedule removed" in f"{response.json()}"
1323
1324 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1325 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1326 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1327 1
    async def test_delete_schedule_archived(self, *args):
1328
        """Test create a circuit schedule."""
1329 1
        (
1330
            validate_mock,
1331
            evc_as_dict_mock,
1332
            uni_from_dict_mock,
1333
        ) = args
1334
1335 1
        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 1
        validate_mock.return_value = True
1353 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1354 1
        evc_as_dict_mock.return_value = {}
1355 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1356
1357 1
        requested_schedule_id = "1"
1358 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1359
1360
        # Call URL
1361 1
        response = await self.api_client.delete(url)
1362 1
        assert response.status_code == 409
1363
1364 1
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1365 1
    async def test_delete_schedule_not_found(self, mock_find_evc_by_sched):
1366
        """Test delete a circuit schedule - unexisting."""
1367 1
        mock_find_evc_by_sched.return_value = (None, False)
1368 1
        url = f'{self.base_endpoint}/v2/evc/schedule/1'
1369 1
        response = await self.api_client.delete(url)
1370 1
        assert response.status_code == 404
1371
1372 1
    def test_get_evcs_by_svc_level(self) -> None:
1373
        """Test get_evcs_by_svc_level."""
1374 1
        levels = [1, 2, 4, 2, 7]
1375 1
        evcs = {i: MagicMock(service_level=v, creation_time=1)
1376
                for i, v in enumerate(levels)}
1377 1
        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 1
        assert evcs_by_level
1381
1382 1
        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
                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 1
            assert evcs_by_level[i].creation_time == i
1391
1392 1
    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 1
        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
1399 1
    @patch('requests.post')
1400 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1401 1
    @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 1
    @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 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1409 1
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1410 1
    async def test_update_circuit(
1411
        self,
1412
        evc_as_dict_mock,
1413
        uni_from_dict_mock,
1414
        evc_deploy,
1415
        _is_valid_mock,
1416
        interface_by_id_mock,
1417
        _mock_validate,
1418
        _mongo_controller_upsert_mock,
1419
        _mongo_controller_update_mock,
1420
        _sched_add_mock,
1421
        mock_use_uni_tags,
1422
        requests_mock,
1423
        event_loop,
1424
    ):
1425
        """Test update a circuit circuit."""
1426 1
        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
            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
        ]
1433 1
        uni_from_dict_mock.side_effect = 2 * unis
1434
1435 1
        response = MagicMock()
1436 1
        response.status_code = 201
1437 1
        requests_mock.return_value = response
1438
1439 1
        payloads = [
1440
            {
1441
                "name": "my evc1",
1442
                "uni_a": {
1443
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1444
                    "tag": {"tag_type": 'vlan', "value": 80},
1445
                },
1446
                "uni_z": {
1447
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1448
                    "tag": {"tag_type": 'vlan', "value": 1},
1449
                },
1450
                "dynamic_backup_path": True,
1451
            },
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
            {
1464
                # It works only with 'enable' and not with 'enabled'
1465
                "enable": True
1466
            },
1467
            {
1468
                "name": "my evc1",
1469
                "active": True,
1470
                "enable": True,
1471
                "uni_a": {
1472
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1473
                    "tag": {
1474
                        "tag_type": 'vlan',
1475
                        "value": 80
1476
                    }
1477
                },
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
1491 1
        evc_as_dict_mock.return_value = payloads[0]
1492 1
        response = await self.api_client.post(
1493
            f"{self.base_endpoint}/v2/evc/",
1494
            json=payloads[0],
1495
        )
1496 1
        assert 201 == response.status_code
1497
1498 1
        evc_deploy.reset_mock()
1499 1
        evc_as_dict_mock.return_value = payloads[1]
1500 1
        current_data = response.json()
1501 1
        circuit_id = current_data["circuit_id"]
1502 1
        response = await self.api_client.patch(
1503
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1504
            json=payloads[1],
1505
        )
1506
        # evc_deploy.assert_called_once()
1507 1
        assert 200 == response.status_code
1508
1509 1
        evc_deploy.reset_mock()
1510 1
        evc_as_dict_mock.return_value = payloads[2]
1511 1
        response = await self.api_client.patch(
1512
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1513
            json=payloads[2],
1514
        )
1515 1
        evc_deploy.assert_not_called()
1516 1
        assert 200 == response.status_code
1517
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
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1522
            json=payloads[3],
1523
        )
1524 1
        evc_deploy.assert_called_once()
1525 1
        assert 200 == response.status_code
1526
1527 1
        evc_deploy.reset_mock()
1528 1
        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 1
        evc_deploy.assert_not_called()
1534 1
        assert 400 == response.status_code
1535
1536 1
        response = await self.api_client.patch(
1537
            f"{self.base_endpoint}/v2/evc/1234",
1538
            json=payloads[1],
1539
        )
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
1545 1
        await self.api_client.delete(
1546
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1547
        )
1548 1
        evc_deploy.reset_mock()
1549 1
        response = await self.api_client.patch(
1550
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1551
            json=payloads[1],
1552
        )
1553 1
        evc_deploy.assert_not_called()
1554 1
        assert 409 == response.status_code
1555 1
        assert "Can't update archived EVC" in response.json()["description"]
1556
1557 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1558 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1559 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1560 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1561 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1562 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1563 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1564 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1565 1
    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
        mock_use_uni_tags,
1574
        mock_tags_equal,
1575
        event_loop
1576
    ):
1577
        """Test update a circuit circuit."""
1578 1
        self.napp.controller.loop = event_loop
1579 1
        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 1
        mock_tags_equal.return_value = True
1585 1
        uni1 = create_autospec(UNI)
1586 1
        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 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1592
1593 1
        payload1 = {
1594
            "name": "my evc1",
1595
            "uni_a": {
1596
                "interface_id": "00:00:00:00:00:00:00:01:1",
1597
                "tag": {"tag_type": 'vlan', "value": 80},
1598
            },
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 1
        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
            f"{self.base_endpoint}/v2/evc/",
1613
            json=payload1
1614
        )
1615 1
        assert 201 == response.status_code
1616
1617 1
        evc_as_dict_mock.return_value = payload2
1618 1
        current_data = response.json()
1619 1
        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 1
        assert "must have a primary path or" in current_data["description"]
1627
1628 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1629 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1630 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1631 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1632 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1633 1
    @patch("napps.kytos.mef_eline.main.Main._link_from_dict")
1634 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1635 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1636 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1637 1
    @patch("napps.kytos.mef_eline.models.path.Path.is_valid")
1638 1
    async def test_update_circuit_invalid_path(
1639
        self,
1640
        is_valid_mock,
1641
        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
        mock_use_uni_tags,
1649
        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 1
        mongo_controller_upsert_mock.return_value = True
1657 1
        sched_add_mock.return_value = True
1658 1
        evc_deploy_mock.return_value = True
1659 1
        mock_use_uni_tags.return_value = True
1660 1
        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 1
        uni1.interface = create_autospec(Interface)
1665 1
        uni2.interface = create_autospec(Interface)
1666 1
        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 1
        payload1 = {
1671
            "name": "my evc1",
1672
            "uni_a": {
1673
                "interface_id": "00:00:00:00:00:00:00:01:1",
1674
                "tag": {"tag_type": 'vlan', "value": 80},
1675
            },
1676
            "uni_z": {
1677
                "interface_id": "00:00:00:00:00:00:00:02:2",
1678
                "tag": {"tag_type": 'vlan', "value": 1},
1679
            },
1680
            "dynamic_backup_path": True,
1681
        }
1682
1683 1
        payload2 = {
1684
            "primary_path": [
1685
                {
1686
                    "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1687
                    "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1688
                }
1689
            ]
1690
        }
1691
1692 1
        evc_as_dict_mock.return_value = payload1
1693 1
        response = await self.api_client.post(
1694
            f"{self.base_endpoint}/v2/evc/",
1695
            json=payload1,
1696
        )
1697 1
        assert 201 == response.status_code
1698
1699 1
        evc_as_dict_mock.return_value = payload2
1700 1
        current_data = response.json()
1701 1
        circuit_id = current_data["circuit_id"]
1702 1
        response = await self.api_client.patch(
1703
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1704
            json=payload2,
1705
        )
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
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 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1715 1
    @patch('napps.kytos.mef_eline.models.evc.EVCDeploy.deploy')
1716 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1717 1
    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
        with disabled switches or interfaces"""
1729 1
        evc_deploy.return_value = True
1730 1
        _mock_validate.return_value = True
1731 1
        _mongo_controller_upsert_mock.return_value = True
1732 1
        mock_use_uni_tags.return_value = True
1733 1
        self.napp.controller.loop = event_loop
1734
        # Interfaces from get_uni_mocked() are disabled
1735 1
        uni_a = get_uni_mocked(
1736
            switch_dpid="00:00:00:00:00:00:00:01",
1737
            switch_id="00:00:00:00:00:00:00:01"
1738
        )
1739 1
        uni_z = get_uni_mocked(
1740
            switch_dpid="00:00:00:00:00:00:00:02",
1741
            switch_id="00:00:00:00:00:00:00:02"
1742
        )
1743 1
        unis = [uni_a, uni_z]
1744 1
        uni_from_dict_mock.side_effect = 2 * unis
1745
1746 1
        evc_payload = {
1747
            "name": "Intra-EVC",
1748
            "dynamic_backup_path": True,
1749
            "uni_a": {
1750
                "tag": {"value": 101, "tag_type": 'vlan'},
1751
                "interface_id": "00:00:00:00:00:00:00:02:2"
1752
            },
1753
            "uni_z": {
1754
                "tag": {"value": 101, "tag_type": 'vlan'},
1755
                "interface_id": "00:00:00:00:00:00:00:01:1"
1756
            }
1757
        }
1758
1759
        # With this update the EVC will be intra-switch
1760 1
        update_payload = {
1761
            "uni_z": {
1762
                "tag": {"value": 101, "tag_type": 'vlan'},
1763
                "interface_id": "00:00:00:00:00:00:00:02:1"
1764
            }
1765
        }
1766
        # Same mocks = intra-switch
1767 1
        mock_get_unis.return_value = [uni_z, uni_z]
1768 1
        response = await self.api_client.post(
1769
            f"{self.base_endpoint}/v2/evc/",
1770
            json=evc_payload,
1771
        )
1772 1
        assert 201 == response.status_code
1773 1
        current_data = response.json()
1774 1
        circuit_id = current_data["circuit_id"]
1775
1776 1
        response = await self.api_client.patch(
1777
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1778
            json=update_payload,
1779
        )
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
1784 1
    def test_link_from_dict_non_existent_intf(self):
1785
        """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
            "endpoint_a": {"id": "a"},
1789
            "endpoint_b": {"id": "b"}
1790
        }
1791 1
        with pytest.raises(ValueError):
1792 1
            self.napp._link_from_dict(link_dict)
1793
1794 1
    def test_uni_from_dict_non_existent_intf(self):
1795
        """Test _link_from_dict non existent intf."""
1796 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1797 1
        uni_dict = {
1798
            "interface_id": "aaa",
1799
        }
1800 1
        with pytest.raises(ValueError):
1801 1
            self.napp._uni_from_dict(uni_dict)
1802
1803 1 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 1
    @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 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1808 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1809 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1810 1
    async def test_update_evc_no_json_mime(
1811
        self,
1812
        mongo_controller_upsert_mock,
1813
        validate_mock,
1814
        uni_from_dict_mock,
1815
        sched_add_mock,
1816
        evc_deploy_mock,
1817
        mock_use_uni_tags,
1818
        mock_tags_equal,
1819
        event_loop
1820
    ):
1821
        """Test update a circuit with wrong mimetype."""
1822 1
        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 1
        mock_tags_equal.return_value = True
1828 1
        uni1 = create_autospec(UNI)
1829 1
        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 1
        mongo_controller_upsert_mock.return_value = True
1836
1837 1
        payload1 = {
1838
            "name": "my evc1",
1839
            "uni_a": {
1840
                "interface_id": "00:00:00:00:00:00:00:01:1",
1841
                "tag": {"tag_type": 'vlan', "value": 80},
1842
            },
1843
            "uni_z": {
1844
                "interface_id": "00:00:00:00:00:00:00:02:2",
1845
                "tag": {"tag_type": 'vlan', "value": 1},
1846
            },
1847
            "dynamic_backup_path": True,
1848
        }
1849
1850 1
        payload2 = {"dynamic_backup_path": False}
1851
1852 1
        response = await self.api_client.post(
1853
            f"{self.base_endpoint}/v2/evc/",
1854
            json=payload1,
1855
        )
1856 1
        assert 201 == response.status_code
1857
1858 1
        current_data = response.json()
1859 1
        circuit_id = current_data["circuit_id"]
1860 1
        response = await self.api_client.patch(
1861
            f"{self.base_endpoint}/v2/evc/{circuit_id}", data=payload2
1862
        )
1863 1
        current_data = response.json()
1864 1
        assert 415 == response.status_code
1865 1
        assert "application/json" in current_data["description"]
1866
1867 1
    async def test_delete_no_evc(self):
1868
        """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 1
        assert current_data["description"] == expected_data
1874 1
        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 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1882 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1883 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1884 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1885 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1886 1
    async def test_delete_archived_evc(
1887
        self,
1888
        evc_as_dict_mock,
1889
        validate_mock,
1890
        mongo_controller_upsert_mock,
1891
        uni_from_dict_mock,
1892
        sched_add_mock,
1893
        evc_deploy_mock,
1894
        remove_current_flows_mock,
1895
        mock_remove_tags,
1896
        mock_use_uni,
1897
        mock_tags_equal,
1898
        event_loop
1899
    ):
1900
        """Try to delete an archived EVC"""
1901 1
        self.napp.controller.loop = event_loop
1902 1
        validate_mock.return_value = True
1903 1
        mongo_controller_upsert_mock.return_value = True
1904 1
        sched_add_mock.return_value = True
1905 1
        evc_deploy_mock.return_value = True
1906 1
        remove_current_flows_mock.return_value = True
1907 1
        mock_use_uni.return_value = True
1908 1
        mock_tags_equal.return_value = True
1909 1
        uni1 = create_autospec(UNI)
1910 1
        uni2 = create_autospec(UNI)
1911 1
        uni1.interface = create_autospec(Interface)
1912 1
        uni2.interface = create_autospec(Interface)
1913 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1914 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1915 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1916
1917 1
        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 1
        evc_as_dict_mock.return_value = payload1
1931 1
        response = await self.api_client.post(
1932
            f"{self.base_endpoint}/v2/evc/",
1933
            json=payload1
1934
        )
1935 1
        assert 201 == response.status_code
1936
1937 1
        current_data = response.json()
1938 1
        circuit_id = current_data["circuit_id"]
1939 1
        response = await self.api_client.delete(
1940
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1941
        )
1942 1
        assert 200 == response.status_code
1943 1
        assert mock_remove_tags.call_count == 1
1944
1945 1
        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 1
        assert current_data["description"] == expected_data
1951 1
        assert 404 == response.status_code
1952
1953 1
    def test_handle_link_up(self):
1954
        """Test handle_link_up method."""
1955 1
        evc_mock = create_autospec(EVC)
1956 1
        evc_mock.service_level, evc_mock.creation_time = 0, 1
1957 1
        evc_mock.is_enabled = MagicMock(side_effect=[True, False, True])
1958 1
        evc_mock.lock = MagicMock()
1959 1
        type(evc_mock).archived = PropertyMock(
1960
            side_effect=[True, False, False]
1961
        )
1962 1
        evcs = [evc_mock, evc_mock, evc_mock]
1963 1
        event = KytosEvent(name="test", content={"link": "abc"})
1964 1
        self.napp.circuits = dict(zip(["1", "2", "3"], evcs))
1965 1
        self.napp.handle_link_up(event)
1966 1
        evc_mock.handle_link_up.assert_called_once_with("abc")
1967
1968 1
    @patch("time.sleep", return_value=None)
1969 1
    @patch("napps.kytos.mef_eline.main.settings")
1970 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1971 1
    def test_handle_link_down(self, emit_event_mock, settings_mock, _):
1972
        """Test handle_link_down method."""
1973 1
        uni = create_autospec(UNI)
1974 1
        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 1
        evc1.name = "name"
1978 1
        evc1.is_affected_by_link.return_value = True
1979 1
        evc1.handle_link_down.return_value = True
1980 1
        evc1.failover_path = None
1981 1
        evc2 = MagicMock(id="2", service_level=6, creation_time=1)
1982 1
        evc2.is_affected_by_link.return_value = False
1983 1
        evc3 = MagicMock(id="3", service_level=5, creation_time=1,
1984
                         metadata="mock", _active="true", _enabled="true",
1985
                         uni_a=uni, uni_z=uni)
1986 1
        evc3.name = "name"
1987 1
        evc3.is_affected_by_link.return_value = True
1988 1
        evc3.handle_link_down.return_value = True
1989 1
        evc3.failover_path = None
1990 1
        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 1
        evc4.name = "name"
1994 1
        evc4.is_affected_by_link.return_value = True
1995 1
        evc4.is_failover_path_affected_by_link.return_value = False
1996 1
        evc4.failover_path = ["2"]
1997 1
        evc4.get_failover_flows.return_value = {
1998
            "2": ["flow1", "flow2"],
1999
            "3": ["flow3", "flow4", "flow5", "flow6"],
2000
        }
2001 1
        evc5 = MagicMock(id="5", service_level=7, creation_time=1)
2002 1
        evc5.is_affected_by_link.return_value = True
2003 1
        evc5.is_failover_path_affected_by_link.return_value = False
2004 1
        evc5.failover_path = ["3"]
2005 1
        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
                         metadata="mock", _active="true", _enabled="true",
2011
                         uni_a=uni, uni_z=uni)
2012 1
        evc6.name = "name"
2013 1
        evc6.is_affected_by_link.return_value = True
2014 1
        evc6.is_failover_path_affected_by_link.return_value = False
2015 1
        evc6.failover_path = ["3"]
2016 1
        evc6.get_failover_flows.side_effect = AttributeError("err")
2017 1
        link = MagicMock(id="123")
2018 1
        event = KytosEvent(name="test", content={"link": link})
2019 1
        self.napp.circuits = {"1": evc1, "2": evc2, "3": evc3, "4": evc4,
2020
                              "5": evc5, "6": evc6}
2021 1
        settings_mock.BATCH_SIZE = 2
2022 1
        self.napp.handle_link_down(event)
2023
2024 1
        assert evc5.service_level > evc4.service_level
2025
        # evc5 batched flows should be sent first
2026 1
        emit_event_mock.assert_has_calls([
2027
            call(
2028
                self.napp.controller,
2029
                context="kytos.flow_manager",
2030
                name="flows.install",
2031
                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
                }
2044
            ),
2045
            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
                name="flows.install",
2058
                content={
2059
                    "dpid": "3",
2060
                    "flow_dict": {"flows": ["flow3", "flow4"]},
2061
                }
2062
            ),
2063
            call(
2064
                self.napp.controller,
2065
                context="kytos.flow_manager",
2066
                name="flows.install",
2067
                content={
2068
                    "dpid": "3",
2069
                    "flow_dict": {"flows": ["flow5", "flow6"]},
2070
                }
2071
            ),
2072
        ])
2073 1
        event_name = "evc_affected_by_link_down"
2074 1
        assert evc3.service_level > evc1.service_level
2075
        # evc3 should be handled before evc1
2076 1
        emit_event_mock.assert_has_calls([
2077
            call(self.napp.controller, event_name, content={
2078
                "link_id": "123",
2079
                "evc_id": "6",
2080
                "name": "name",
2081
                "metadata": "mock",
2082
                "active": "true",
2083
                "enabled": "true",
2084
                "uni_a": uni.as_dict(),
2085
                "uni_z": uni.as_dict(),
2086
            }),
2087
            call(self.napp.controller, event_name, content={
2088
                "link_id": "123",
2089
                "evc_id": "3",
2090
                "name": "name",
2091
                "metadata": "mock",
2092
                "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
                "link_id": "123",
2099
                "evc_id": "1",
2100
                "name": "name",
2101
                "metadata": "mock",
2102
                "active": "true",
2103
                "enabled": "true",
2104
                "uni_a": uni.as_dict(),
2105
                "uni_z": uni.as_dict(),
2106
            }),
2107
        ])
2108 1
        evc4.sync.assert_called_once()
2109 1
        event_name = "redeployed_link_down"
2110 1
        emit_event_mock.assert_has_calls([
2111
            call(self.napp.controller, event_name, content={
2112
                "evc_id": "4",
2113
                "name": "name",
2114
                "metadata": "mock",
2115
                "active": "true",
2116
                "enabled": "true",
2117
                "uni_a": uni.as_dict(),
2118
                "uni_z": uni.as_dict(),
2119
            }),
2120
        ])
2121
2122 1
    @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
            id="1",
2128
            metadata="data_mocked",
2129
            _active="true",
2130
            _enabled="false",
2131
            uni_a=uni,
2132
            uni_z=uni,
2133
        )
2134 1
        evc1.name = "name_mocked"
2135 1
        evc1.handle_link_down.return_value = True
2136 1
        evc2 = MagicMock(
2137
            id="2",
2138
            metadata="mocked_data",
2139
            _active="false",
2140
            _enabled="true",
2141
            uni_a=uni,
2142
            uni_z=uni,
2143
        )
2144 1
        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
            "link_id": "1",
2151
        })
2152 1
        self.napp.handle_evc_affected_by_link_down(event)
2153 1
        emit_event_mock.assert_not_called()
2154 1
        event.content["evc_id"] = "1"
2155 1
        self.napp.handle_evc_affected_by_link_down(event)
2156 1
        emit_event_mock.assert_called_with(
2157
            self.napp.controller, "redeployed_link_down", content={
2158
                "evc_id": "1",
2159
                "name": "name_mocked",
2160
                "metadata": "data_mocked",
2161
                "active": "true",
2162
                "enabled": "false",
2163
                "uni_a": uni.as_dict(),
2164
                "uni_z": uni.as_dict(),
2165
            }
2166
        )
2167
2168 1
        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
                "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
        )
2181
2182 1
    def test_handle_evc_deployed(self):
2183
        """Test handle_evc_deployed method."""
2184 1
        evc = create_autospec(EVC, id="1")
2185 1
        evc.lock = MagicMock()
2186 1
        self.napp.circuits = {"1": evc}
2187
2188 1
        event = KytosEvent(name="e1", content={"evc_id": "2"})
2189 1
        self.napp.handle_evc_deployed(event)
2190 1
        evc.setup_failover_path.assert_not_called()
2191
2192 1
        event.content["evc_id"] = "1"
2193 1
        self.napp.handle_evc_deployed(event)
2194 1
        evc.setup_failover_path.assert_called()
2195
2196 1
    async def test_add_metadata(self, event_loop):
2197
        """Test method to add metadata"""
2198 1
        self.napp.controller.loop = event_loop
2199 1
        evc_mock = create_autospec(EVC)
2200 1
        evc_mock.metadata = {}
2201 1
        evc_mock.id = 1234
2202 1
        self.napp.circuits = {"1234": evc_mock}
2203
2204 1
        payload = {"metadata1": 1, "metadata2": 2}
2205 1
        response = await self.api_client.post(
2206
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2207
            json=payload
2208
        )
2209
2210 1
        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
        """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
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2219
            content=payload,
2220
            headers={"Content-Type": "application/json"}
2221
        )
2222
2223 1
        assert response.status_code == 400
2224 1
        assert "Failed to deserialize" in response.json()["description"]
2225
2226 1
    async def test_add_metadata_no_body(self, event_loop):
2227
        """Test method to add metadata with no body"""
2228 1
        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 1
    async def test_add_metadata_no_evc(self, event_loop):
2237
        """Test method to add metadata with no evc"""
2238 1
        self.napp.controller.loop = event_loop
2239 1
        payload = {"metadata1": 1, "metadata2": 2}
2240 1
        response = await self.api_client.post(
2241
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2242
            json=payload,
2243
        )
2244 1
        assert response.status_code == 404
2245 1
        assert response.json()["description"] == \
2246
            "circuit_id 1234 not found."
2247
2248 1
    async def test_add_metadata_wrong_content_type(self, event_loop):
2249
        """Test method to add metadata with wrong content type"""
2250 1
        self.napp.controller.loop = event_loop
2251 1
        payload = {"metadata1": 1, "metadata2": 2}
2252 1
        response = await self.api_client.post(
2253
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2254
            data=payload,
2255
            headers={"Content-Type": "application/xml"}
2256
        )
2257 1
        assert response.status_code == 415
2258 1
        assert "application/xml" in response.json()["description"]
2259
2260 1
    async def test_get_metadata(self):
2261
        """Test method to get metadata"""
2262 1
        evc_mock = create_autospec(EVC)
2263 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2264 1
        evc_mock.id = 1234
2265 1
        self.napp.circuits = {"1234": evc_mock}
2266
2267 1
        response = await self.api_client.get(
2268
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2269
        )
2270 1
        assert response.status_code == 200
2271 1
        assert response.json() == {"metadata": evc_mock.metadata}
2272
2273 1
    async def test_delete_metadata(self):
2274
        """Test method to delete metadata"""
2275 1
        evc_mock = create_autospec(EVC)
2276 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2277 1
        evc_mock.id = 1234
2278 1
        self.napp.circuits = {"1234": evc_mock}
2279
2280 1
        response = await self.api_client.delete(
2281
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2282
        )
2283 1
        assert response.status_code == 200
2284
2285 1
    async def test_delete_metadata_no_evc(self):
2286
        """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
        )
2290 1
        assert response.status_code == 404
2291 1
        assert response.json()["description"] == \
2292
            "circuit_id 1234 not found."
2293
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 1
        mock_circuits = {
2298
            'circuits': {
2299
                1: 'circuit_1',
2300
                2: 'circuit_2',
2301
                3: 'circuit_3',
2302
                4: 'circuit_4'
2303
            }
2304
        }
2305 1
        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
2310 1
    @patch('napps.kytos.mef_eline.main.Main._evc_from_dict')
2311 1
    def test_load_evc(self, evc_from_dict_mock):
2312
        """Test _load_evc method"""
2313
        # pylint: disable=protected-access
2314
        # case 1: early return with ValueError exception
2315 1
        evc_from_dict_mock.side_effect = ValueError("err")
2316 1
        evc_dict = MagicMock()
2317 1
        assert not self.napp._load_evc(evc_dict)
2318
2319
        # case 2: early return with KytosTagError exception
2320 1
        evc_from_dict_mock.side_effect = KytosTagError("")
2321 1
        assert not self.napp._load_evc(evc_dict)
2322
2323
        # case 3: archived evc
2324 1
        evc = MagicMock()
2325 1
        evc.archived = True
2326 1
        evc_from_dict_mock.side_effect = None
2327 1
        evc_from_dict_mock.return_value = evc
2328 1
        assert not self.napp._load_evc(evc_dict)
2329
2330
        # case 4: success creating
2331 1
        evc.archived = False
2332 1
        evc.id = 1
2333 1
        self.napp.sched = MagicMock()
2334
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
2340 1
    def test_handle_flow_mod_error(self):
2341
        """Test handle_flow_mod_error method"""
2342 1
        flow = MagicMock()
2343 1
        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 1
        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
        """Test _uni_from_dict method."""
2356
        # pylint: disable=protected-access
2357
        # case1: early return on empty dict
2358 1
        assert not self.napp._uni_from_dict(None)
2359
2360
        # case2: invalid interface raises ValueError
2361 1
        _get_interface_by_id_mock.return_value = None
2362 1
        uni_dict = {
2363
            "interface_id": "00:01:1",
2364
            "tag": {"tag_type": 'vlan', "value": 81},
2365
        }
2366 1
        with pytest.raises(ValueError):
2367 1
            self.napp._uni_from_dict(uni_dict)
2368
2369
        # case3: success creation
2370 1
        uni_mock = get_uni_mocked(switch_id="00:01")
2371 1
        _get_interface_by_id_mock.return_value = uni_mock.interface
2372 1
        uni = self.napp._uni_from_dict(uni_dict)
2373 1
        assert uni == uni_mock
2374
2375
        # case4: success creation of tag list
2376 1
        uni_dict["tag"]["value"] = [[1, 10]]
2377 1
        uni = self.napp._uni_from_dict(uni_dict)
2378 1
        assert isinstance(uni.user_tag, TAGRange)
2379
2380
        # case5: success creation without tag
2381 1
        uni_mock.user_tag = None
2382 1
        del uni_dict["tag"]
2383 1
        uni = self.napp._uni_from_dict(uni_dict)
2384 1
        assert uni == uni_mock
2385
2386 1
    def test_handle_flow_delete(self):
2387
        """Test handle_flow_delete method"""
2388 1
        flow = MagicMock()
2389 1
        flow.cookie = 0xaa00000000000011
2390 1
        event = MagicMock()
2391 1
        event.content = {'flow': flow}
2392 1
        evc = create_autospec(EVC)
2393 1
        evc.set_flow_removed_at = MagicMock()
2394 1
        self.napp.circuits = {"00000000000011": evc}
2395 1
        self.napp.handle_flow_delete(event)
2396 1
        evc.set_flow_removed_at.assert_called_once()
2397
2398 1 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 1
        self.napp.controller.loop = event_loop
2401 1
        evc_mock = create_autospec(EVC)
2402 1
        evc_mock.id = 1234
2403 1
        self.napp.circuits = {"1234": evc_mock}
2404 1
        payload = {
2405
            "circuit_ids": ["1234"],
2406
            "metadata1": 1,
2407
            "metadata2": 2
2408
        }
2409 1
        response = await self.api_client.post(
2410
            f"{self.base_endpoint}/v2/evc/metadata",
2411
            json=payload
2412
        )
2413 1
        assert response.status_code == 201
2414 1
        args = self.napp.mongo_controller.update_evcs.call_args[0]
2415 1
        ids = payload.pop("circuit_ids")
2416 1
        assert args[0] == ids
2417 1
        assert args[1] == payload
2418 1
        assert args[2] == "add"
2419 1
        calls = self.napp.mongo_controller.update_evcs.call_count
2420 1
        assert calls == 1
2421 1
        evc_mock.extend_metadata.assert_called_with(payload)
2422
2423 1
    async def test_add_bulk_metadata_no_id(self, event_loop):
2424
        """Test add_bulk_metadata with unknown evc id"""
2425 1
        self.napp.controller.loop = event_loop
2426 1
        evc_mock = create_autospec(EVC)
2427 1
        evc_mock.id = 1234
2428 1
        self.napp.circuits = {"1234": evc_mock}
2429 1
        payload = {
2430
            "circuit_ids": ["1234", "4567"]
2431
        }
2432 1
        response = await self.api_client.post(
2433
            f"{self.base_endpoint}/v2/evc/metadata",
2434
            json=payload
2435
        )
2436 1
        assert response.status_code == 404
2437
2438 1
    async def test_add_bulk_metadata_no_circuits(self, event_loop):
2439
        """Test add_bulk_metadata without circuit_ids"""
2440 1
        self.napp.controller.loop = event_loop
2441 1
        evc_mock = create_autospec(EVC)
2442 1
        evc_mock.id = 1234
2443 1
        self.napp.circuits = {"1234": evc_mock}
2444 1
        payload = {
2445
            "metadata": "data"
2446
        }
2447 1
        response = await self.api_client.post(
2448
            f"{self.base_endpoint}/v2/evc/metadata",
2449
            json=payload
2450
        )
2451 1
        assert response.status_code == 400
2452
2453 1 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 1
        self.napp.controller.loop = event_loop
2456 1
        evc_mock = create_autospec(EVC)
2457 1
        evc_mock.id = 1234
2458 1
        self.napp.circuits = {"1234": evc_mock}
2459 1
        payload = {
2460
            "circuit_ids": ["1234"]
2461
        }
2462 1
        response = await self.api_client.request(
2463
            "DELETE",
2464
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2465
            json=payload
2466
        )
2467 1
        assert response.status_code == 200
2468 1
        args = self.napp.mongo_controller.update_evcs.call_args[0]
2469 1
        assert args[0] == payload["circuit_ids"]
2470 1
        assert args[1] == {"metadata1": ""}
2471 1
        assert args[2] == "del"
2472 1
        calls = self.napp.mongo_controller.update_evcs.call_count
2473 1
        assert calls == 1
2474 1
        assert evc_mock.remove_metadata.call_count == 1
2475
2476 1
    async def test_delete_bulk_metadata_error(self, event_loop):
2477
        """Test bulk_delete_metadata with ciruit erroring"""
2478 1
        self.napp.controller.loop = event_loop
2479 1
        evc_mock = create_autospec(EVC)
2480 1
        evcs = [evc_mock, evc_mock]
2481 1
        self.napp.circuits = dict(zip(["1", "2"], evcs))
2482 1
        payload = {"circuit_ids": ["1", "2", "3"]}
2483 1
        response = await self.api_client.request(
2484
            "DELETE",
2485
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2486
            json=payload
2487
        )
2488 1
        assert response.status_code == 404, response.data
2489 1
        assert response.json()["description"] == ["3"]
2490
2491 1
    async def test_use_uni_tags(self, event_loop):
2492
        """Test _use_uni_tags"""
2493 1
        self.napp.controller.loop = event_loop
2494 1
        evc_mock = create_autospec(EVC)
2495 1
        evc_mock.uni_a = "uni_a_mock"
2496 1
        evc_mock.uni_z = "uni_z_mock"
2497 1
        self.napp._use_uni_tags(evc_mock)
2498 1
        assert evc_mock._use_uni_vlan.call_count == 2
2499 1
        assert evc_mock._use_uni_vlan.call_args[0][0] == evc_mock.uni_z
2500
2501
        # One UNI tag is not available
2502 1
        evc_mock._use_uni_vlan.side_effect = [KytosTagError(""), None]
2503 1
        with pytest.raises(KytosTagError):
2504 1
            self.napp._use_uni_tags(evc_mock)
2505 1
        assert evc_mock._use_uni_vlan.call_count == 3
2506 1
        assert evc_mock.make_uni_vlan_available.call_count == 0
2507
2508 1
        evc_mock._use_uni_vlan.side_effect = [None, KytosTagError("")]
2509 1
        with pytest.raises(KytosTagError):
2510 1
            self.napp._use_uni_tags(evc_mock)
2511 1
        assert evc_mock._use_uni_vlan.call_count == 5
2512
        assert evc_mock.make_uni_vlan_available.call_count == 1
2513