Passed
Pull Request — master (#438)
by Italo Valcy
03:55
created

TestMain.test_create_schedule()   B

Complexity

Conditions 1

Size

Total Lines 58
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 1

Importance

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