Passed
Pull Request — master (#433)
by
unknown
04:15
created

TestMain.test_update_circuit()   B

Complexity

Conditions 1

Size

Total Lines 135
Code Lines 98

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 54
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 98
nop 13
dl 0
loc 135
ccs 54
cts 54
cp 1
crap 1
rs 7.0654
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
    async def test_get_circuit_not_found(self):
1294
        """Test /v2/evc/<circuit_id> 404."""
1295 1
        self.napp.mongo_controller.get_circuit.return_value = None
1296 1
        url = f'{self.base_endpoint}/v2/evc/1234'
1297 1
        response = await self.api_client.get(url)
1298 1
        assert response.status_code == 404
1299
1300 1
    @patch('requests.post')
1301 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1302 1
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1303 1
    @patch('napps.kytos.mef_eline.controllers.ELineController.update_evc')
1304 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1305 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1306 1
    @patch('kytos.core.Controller.get_interface_by_id')
1307 1
    @patch('napps.kytos.mef_eline.models.path.Path.is_valid')
1308 1
    @patch('napps.kytos.mef_eline.models.evc.EVCDeploy.deploy')
1309 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1310 1
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1311 1
    async def test_update_circuit(
1312
        self,
1313
        evc_as_dict_mock,
1314
        uni_from_dict_mock,
1315
        evc_deploy,
1316
        _is_valid_mock,
1317
        interface_by_id_mock,
1318
        _mock_validate,
1319
        _mongo_controller_upsert_mock,
1320
        _mongo_controller_update_mock,
1321
        _sched_add_mock,
1322
        mock_use_uni_tags,
1323
        requests_mock,
1324
        event_loop,
1325
    ):
1326
        """Test update a circuit circuit."""
1327 1
        self.napp.controller.loop = event_loop
1328 1
        mock_use_uni_tags.return_value = True
1329 1
        interface_by_id_mock.return_value = get_uni_mocked().interface
1330 1
        unis = [
1331
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:01"),
1332
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:02"),
1333
        ]
1334 1
        uni_from_dict_mock.side_effect = 2 * unis
1335
1336 1
        response = MagicMock()
1337 1
        response.status_code = 201
1338 1
        requests_mock.return_value = response
1339
1340 1
        payloads = [
1341
            {
1342
                "name": "my evc1",
1343
                "uni_a": {
1344
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1345
                    "tag": {"tag_type": 'vlan', "value": 80},
1346
                },
1347
                "uni_z": {
1348
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1349
                    "tag": {"tag_type": 'vlan', "value": 1},
1350
                },
1351
                "dynamic_backup_path": True,
1352
            },
1353
            {
1354
                "primary_path": [
1355
                    {
1356
                        "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1357
                        "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1358
                    }
1359
                ]
1360
            },
1361
            {
1362
                "sb_priority": 3
1363
            },
1364
            {
1365
                # It works only with 'enable' and not with 'enabled'
1366
                "enable": True
1367
            },
1368
            {
1369
                "sb_priority": 100
1370
            }
1371
        ]
1372
1373 1
        evc_as_dict_mock.return_value = payloads[0]
1374 1
        response = await self.api_client.post(
1375
            f"{self.base_endpoint}/v2/evc/",
1376
            json=payloads[0],
1377
        )
1378 1
        assert 201 == response.status_code
1379
1380 1
        evc_deploy.reset_mock()
1381 1
        evc_as_dict_mock.return_value = payloads[1]
1382 1
        current_data = response.json()
1383 1
        circuit_id = current_data["circuit_id"]
1384 1
        response = await self.api_client.patch(
1385
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1386
            json=payloads[1],
1387
        )
1388
        # evc_deploy.assert_called_once()
1389 1
        assert 200 == response.status_code
1390
1391 1
        evc_deploy.reset_mock()
1392 1
        evc_as_dict_mock.return_value = payloads[2]
1393 1
        response = await self.api_client.patch(
1394
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1395
            json=payloads[2],
1396
        )
1397 1
        evc_deploy.assert_not_called()
1398 1
        assert 200 == response.status_code
1399
1400 1
        evc_deploy.reset_mock()
1401 1
        evc_as_dict_mock.return_value = payloads[3]
1402 1
        response = await self.api_client.patch(
1403
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1404
            json=payloads[3],
1405
        )
1406 1
        evc_deploy.assert_called_once()
1407 1
        assert 200 == response.status_code
1408
1409 1
        evc_deploy.reset_mock()
1410 1
        response = await self.api_client.patch(
1411
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1412
            content=b'{"priority":5,}',
1413
            headers={"Content-Type": "application/json"}
1414
        )
1415 1
        evc_deploy.assert_not_called()
1416 1
        assert 400 == response.status_code
1417
1418 1
        response = await self.api_client.patch(
1419
            f"{self.base_endpoint}/v2/evc/1234",
1420
            json=payloads[1],
1421
        )
1422 1
        current_data = response.json()
1423 1
        expected_data = "circuit_id 1234 not found"
1424 1
        assert current_data["description"] == expected_data
1425 1
        assert 404 == response.status_code
1426
1427 1
        self.napp.circuits[circuit_id]._active = False
1428 1
        evc_deploy.reset_mock()
1429 1
        response = await self.api_client.patch(
1430
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1431
            json=payloads[4]
1432
        )
1433 1
        assert 200 == response.status_code
1434 1
        evc_deploy.assert_called_once()
1435
1436 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...
1437 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1438 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1439 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1440 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1441 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1442 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1443 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1444 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1445 1
    async def test_update_circuit_invalid_json(
1446
        self,
1447
        evc_as_dict_mock,
1448
        validate_mock,
1449
        mongo_controller_upsert_mock,
1450
        uni_from_dict_mock,
1451
        sched_add_mock,
1452
        evc_deploy_mock,
1453
        mock_use_uni_tags,
1454
        mock_tags_equal,
1455
        mock_check_duplicate,
1456
        event_loop
1457
    ):
1458
        """Test update a circuit circuit."""
1459 1
        self.napp.controller.loop = event_loop
1460 1
        validate_mock.return_value = True
1461 1
        mongo_controller_upsert_mock.return_value = True
1462 1
        sched_add_mock.return_value = True
1463 1
        evc_deploy_mock.return_value = True
1464 1
        mock_use_uni_tags.return_value = True
1465 1
        mock_tags_equal.return_value = True
1466 1
        mock_check_duplicate.return_value = True
1467 1
        uni1 = create_autospec(UNI)
1468 1
        uni2 = create_autospec(UNI)
1469 1
        uni1.interface = create_autospec(Interface)
1470 1
        uni2.interface = create_autospec(Interface)
1471 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1472 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1473 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1474
1475 1
        payload1 = {
1476
            "name": "my evc1",
1477
            "uni_a": {
1478
                "interface_id": "00:00:00:00:00:00:00:01:1",
1479
                "tag": {"tag_type": 'vlan', "value": 80},
1480
            },
1481
            "uni_z": {
1482
                "interface_id": "00:00:00:00:00:00:00:02:2",
1483
                "tag": {"tag_type": 'vlan', "value": 1},
1484
            },
1485
            "dynamic_backup_path": True,
1486
        }
1487
1488 1
        payload2 = {
1489
            "dynamic_backup_path": False,
1490
        }
1491
1492 1
        evc_as_dict_mock.return_value = payload1
1493 1
        response = await self.api_client.post(
1494
            f"{self.base_endpoint}/v2/evc/",
1495
            json=payload1
1496
        )
1497 1
        assert 201 == response.status_code
1498
1499 1
        evc_as_dict_mock.return_value = payload2
1500 1
        current_data = response.json()
1501 1
        circuit_id = current_data["circuit_id"]
1502 1
        response = await self.api_client.patch(
1503
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1504
            json=payload2
1505
        )
1506 1
        current_data = response.json()
1507 1
        assert 400 == response.status_code
1508 1
        assert "must have a primary path or" in current_data["description"]
1509
1510 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
1511 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1512 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1513 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1514 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1515 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1516 1
    @patch("napps.kytos.mef_eline.main.Main._link_from_dict")
1517 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1518 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1519 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1520 1
    @patch("napps.kytos.mef_eline.models.path.Path.is_valid")
1521 1
    async def test_update_circuit_invalid_path(
1522
        self,
1523
        is_valid_mock,
1524
        evc_as_dict_mock,
1525
        validate_mock,
1526
        mongo_controller_upsert_mock,
1527
        link_from_dict_mock,
1528
        uni_from_dict_mock,
1529
        sched_add_mock,
1530
        evc_deploy_mock,
1531
        mock_use_uni_tags,
1532
        mock_tags_equal,
1533
        mock_check_duplicate,
1534
        event_loop
1535
    ):
1536
        """Test update a circuit circuit."""
1537 1
        self.napp.controller.loop = event_loop
1538 1
        is_valid_mock.side_effect = InvalidPath("error")
1539 1
        validate_mock.return_value = True
1540 1
        mongo_controller_upsert_mock.return_value = True
1541 1
        sched_add_mock.return_value = True
1542 1
        evc_deploy_mock.return_value = True
1543 1
        mock_use_uni_tags.return_value = True
1544 1
        link_from_dict_mock.return_value = 1
1545 1
        mock_tags_equal.return_value = True
1546 1
        mock_check_duplicate.return_value = True
1547 1
        uni1 = create_autospec(UNI)
1548 1
        uni2 = create_autospec(UNI)
1549 1
        uni1.interface = create_autospec(Interface)
1550 1
        uni2.interface = create_autospec(Interface)
1551 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1552 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1553 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1554
1555 1
        payload1 = {
1556
            "name": "my evc1",
1557
            "uni_a": {
1558
                "interface_id": "00:00:00:00:00:00:00:01:1",
1559
                "tag": {"tag_type": 'vlan', "value": 80},
1560
            },
1561
            "uni_z": {
1562
                "interface_id": "00:00:00:00:00:00:00:02:2",
1563
                "tag": {"tag_type": 'vlan', "value": 1},
1564
            },
1565
            "dynamic_backup_path": True,
1566
        }
1567
1568 1
        payload2 = {
1569
            "primary_path": [
1570
                {
1571
                    "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1572
                    "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1573
                }
1574
            ]
1575
        }
1576
1577 1
        evc_as_dict_mock.return_value = payload1
1578 1
        response = await self.api_client.post(
1579
            f"{self.base_endpoint}/v2/evc/",
1580
            json=payload1,
1581
        )
1582 1
        assert 201 == response.status_code
1583
1584 1
        evc_as_dict_mock.return_value = payload2
1585 1
        current_data = response.json()
1586 1
        circuit_id = current_data["circuit_id"]
1587 1
        response = await self.api_client.patch(
1588
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1589
            json=payload2,
1590
        )
1591 1
        current_data = response.json()
1592 1
        expected_data = "primary_path is not a valid path: error"
1593 1
        assert 400 == response.status_code
1594 1
        assert current_data["description"] == expected_data
1595
1596 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._get_unis_use_tags")
1597 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1598 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1599 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1600 1
    @patch('napps.kytos.mef_eline.models.evc.EVCDeploy.deploy')
1601 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1602 1
    async def test_update_disabled_intra_switch(
1603
        self,
1604
        uni_from_dict_mock,
1605
        evc_deploy,
1606
        _mock_validate,
1607
        _mongo_controller_upsert_mock,
1608
        mock_use_uni_tags,
1609
        mock_get_unis,
1610
        event_loop,
1611
    ):
1612
        """Test update a circuit that result in an intra-switch EVC
1613
        with disabled switches or interfaces"""
1614 1
        evc_deploy.return_value = True
1615 1
        _mock_validate.return_value = True
1616 1
        _mongo_controller_upsert_mock.return_value = True
1617 1
        mock_use_uni_tags.return_value = True
1618 1
        self.napp.controller.loop = event_loop
1619
        # Interfaces from get_uni_mocked() are disabled
1620 1
        uni_a = get_uni_mocked(
1621
            switch_dpid="00:00:00:00:00:00:00:01",
1622
            switch_id="00:00:00:00:00:00:00:01"
1623
        )
1624 1
        uni_z = get_uni_mocked(
1625
            switch_dpid="00:00:00:00:00:00:00:02",
1626
            switch_id="00:00:00:00:00:00:00:02"
1627
        )
1628 1
        unis = [uni_a, uni_z]
1629 1
        uni_from_dict_mock.side_effect = 2 * unis
1630
1631 1
        evc_payload = {
1632
            "name": "Intra-EVC",
1633
            "dynamic_backup_path": True,
1634
            "uni_a": {
1635
                "tag": {"value": 101, "tag_type": 'vlan'},
1636
                "interface_id": "00:00:00:00:00:00:00:02:2"
1637
            },
1638
            "uni_z": {
1639
                "tag": {"value": 101, "tag_type": 'vlan'},
1640
                "interface_id": "00:00:00:00:00:00:00:01:1"
1641
            }
1642
        }
1643
1644
        # With this update the EVC will be intra-switch
1645 1
        update_payload = {
1646
            "uni_z": {
1647
                "tag": {"value": 101, "tag_type": 'vlan'},
1648
                "interface_id": "00:00:00:00:00:00:00:02:1"
1649
            }
1650
        }
1651
        # Same mocks = intra-switch
1652 1
        mock_get_unis.return_value = [uni_z, uni_z]
1653 1
        response = await self.api_client.post(
1654
            f"{self.base_endpoint}/v2/evc/",
1655
            json=evc_payload,
1656
        )
1657 1
        assert 201 == response.status_code
1658 1
        current_data = response.json()
1659 1
        circuit_id = current_data["circuit_id"]
1660
1661 1
        response = await self.api_client.patch(
1662
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1663
            json=update_payload,
1664
        )
1665 1
        assert 409 == response.status_code
1666 1
        description = "00:00:00:00:00:00:00:02:1 is disabled"
1667 1
        assert description in response.json()["description"]
1668
1669 1
    def test_link_from_dict_non_existent_intf(self):
1670
        """Test _link_from_dict non existent intf."""
1671 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1672 1
        link_dict = {
1673
            "endpoint_a": {"id": "a"},
1674
            "endpoint_b": {"id": "b"}
1675
        }
1676 1
        with pytest.raises(ValueError):
1677 1
            self.napp._link_from_dict(link_dict)
1678
1679 1
    def test_uni_from_dict_non_existent_intf(self):
1680
        """Test _link_from_dict non existent intf."""
1681 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1682 1
        uni_dict = {
1683
            "interface_id": "aaa",
1684
        }
1685 1
        with pytest.raises(ValueError):
1686 1
            self.napp._uni_from_dict(uni_dict)
1687
1688 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...
1689 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1690 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1691 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1692 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1693 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1694 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1695 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1696 1
    async def test_update_evc_no_json_mime(
1697
        self,
1698
        mongo_controller_upsert_mock,
1699
        validate_mock,
1700
        uni_from_dict_mock,
1701
        sched_add_mock,
1702
        evc_deploy_mock,
1703
        mock_use_uni_tags,
1704
        mock_tags_equal,
1705
        mock_check_duplicate,
1706
        event_loop
1707
    ):
1708
        """Test update a circuit with wrong mimetype."""
1709 1
        self.napp.controller.loop = event_loop
1710 1
        validate_mock.return_value = True
1711 1
        sched_add_mock.return_value = True
1712 1
        evc_deploy_mock.return_value = True
1713 1
        mock_use_uni_tags.return_value = True
1714 1
        mock_tags_equal.return_value = True
1715 1
        mock_check_duplicate.return_value = True
1716 1
        uni1 = create_autospec(UNI)
1717 1
        uni2 = create_autospec(UNI)
1718 1
        uni1.interface = create_autospec(Interface)
1719 1
        uni2.interface = create_autospec(Interface)
1720 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1721 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1722 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1723 1
        mongo_controller_upsert_mock.return_value = True
1724
1725 1
        payload1 = {
1726
            "name": "my evc1",
1727
            "uni_a": {
1728
                "interface_id": "00:00:00:00:00:00:00:01:1",
1729
                "tag": {"tag_type": 'vlan', "value": 80},
1730
            },
1731
            "uni_z": {
1732
                "interface_id": "00:00:00:00:00:00:00:02:2",
1733
                "tag": {"tag_type": 'vlan', "value": 1},
1734
            },
1735
            "dynamic_backup_path": True,
1736
        }
1737
1738 1
        payload2 = {"dynamic_backup_path": False}
1739
1740 1
        response = await self.api_client.post(
1741
            f"{self.base_endpoint}/v2/evc/",
1742
            json=payload1,
1743
        )
1744 1
        assert 201 == response.status_code
1745
1746 1
        current_data = response.json()
1747 1
        circuit_id = current_data["circuit_id"]
1748 1
        response = await self.api_client.patch(
1749
            f"{self.base_endpoint}/v2/evc/{circuit_id}", data=payload2
1750
        )
1751 1
        current_data = response.json()
1752 1
        assert 415 == response.status_code
1753 1
        assert "application/json" in current_data["description"]
1754
1755 1
    async def test_delete_no_evc(self):
1756
        """Test delete when EVC does not exist."""
1757 1
        url = f"{self.base_endpoint}/v2/evc/123"
1758 1
        response = await self.api_client.delete(url)
1759 1
        current_data = response.json()
1760 1
        expected_data = "circuit_id 123 not found"
1761 1
        assert current_data["description"] == expected_data
1762 1
        assert 404 == response.status_code
1763
1764 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
1765 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1766 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_uni_tags")
1767 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1768 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_current_flows")
1769 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1770 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1771 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1772 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1773 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1774 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1775 1
    async def test_delete_archived_evc(
1776
        self,
1777
        evc_as_dict_mock,
1778
        validate_mock,
1779
        mongo_controller_upsert_mock,
1780
        uni_from_dict_mock,
1781
        sched_add_mock,
1782
        evc_deploy_mock,
1783
        remove_current_flows_mock,
1784
        mock_remove_tags,
1785
        mock_use_uni,
1786
        mock_tags_equal,
1787
        mock_check_duplicate,
1788
        event_loop
1789
    ):
1790
        """Try to delete an archived EVC"""
1791 1
        self.napp.controller.loop = event_loop
1792 1
        validate_mock.return_value = True
1793 1
        mongo_controller_upsert_mock.return_value = True
1794 1
        sched_add_mock.return_value = True
1795 1
        evc_deploy_mock.return_value = True
1796 1
        remove_current_flows_mock.return_value = True
1797 1
        mock_use_uni.return_value = True
1798 1
        mock_tags_equal.return_value = True
1799 1
        mock_check_duplicate.return_value = True
1800 1
        uni1 = create_autospec(UNI)
1801 1
        uni2 = create_autospec(UNI)
1802 1
        uni1.interface = create_autospec(Interface)
1803 1
        uni2.interface = create_autospec(Interface)
1804 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1805 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1806 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1807
1808 1
        payload1 = {
1809
            "name": "my evc1",
1810
            "uni_a": {
1811
                "interface_id": "00:00:00:00:00:00:00:01:1",
1812
                "tag": {"tag_type": 'vlan', "value": 80},
1813
            },
1814
            "uni_z": {
1815
                "interface_id": "00:00:00:00:00:00:00:02:2",
1816
                "tag": {"tag_type": 'vlan', "value": 1},
1817
            },
1818
            "dynamic_backup_path": True,
1819
        }
1820
1821 1
        evc_as_dict_mock.return_value = payload1
1822 1
        response = await self.api_client.post(
1823
            f"{self.base_endpoint}/v2/evc/",
1824
            json=payload1
1825
        )
1826 1
        assert 201 == response.status_code
1827 1
        assert len(self.napp.circuits) == 1
1828
1829 1
        current_data = response.json()
1830 1
        circuit_id = current_data["circuit_id"]
1831 1
        response = await self.api_client.delete(
1832
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1833
        )
1834 1
        assert 200 == response.status_code
1835 1
        assert mock_remove_tags.call_count == 1
1836 1
        assert len(self.napp.circuits) == 0
1837
1838 1
        response = await self.api_client.delete(
1839
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1840
        )
1841 1
        current_data = response.json()
1842 1
        expected_data = f"circuit_id {circuit_id} not found"
1843 1
        assert current_data["description"] == expected_data
1844 1
        assert 404 == response.status_code
1845 1
        assert len(self.napp.circuits) == 0
1846
1847 1
    def test_handle_link_up(self):
1848
        """Test handle_link_up method."""
1849 1
        evc_mock = create_autospec(EVC)
1850 1
        evc_mock.service_level, evc_mock.creation_time = 0, 1
1851 1
        evc_mock.is_enabled = MagicMock(side_effect=[
1852
            True, False, True, True, True
1853
        ])
1854 1
        evc_mock.lock = MagicMock()
1855 1
        evc_mock.archived = False
1856 1
        evcs = [evc_mock, evc_mock, evc_mock]
1857 1
        event = KytosEvent(name="test", content={"link": "abc"})
1858 1
        self.napp.circuits = dict(zip(["1", "2", "3"], evcs))
1859 1
        self.napp.handle_link_up(event)
1860 1
        assert evc_mock.handle_link_up.call_count == 2
1861 1
        evc_mock.handle_link_up.assert_called_with("abc")
1862
1863 1
    @patch("time.sleep", return_value=None)
1864 1
    @patch("napps.kytos.mef_eline.main.settings")
1865 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1866 1
    def test_handle_link_down(self, emit_event_mock, settings_mock, _):
1867
        """Test handle_link_down method."""
1868 1
        uni = create_autospec(UNI)
1869 1
        evc1 = MagicMock(id="1", service_level=0, creation_time=1,
1870
                         metadata="mock", _active="true", _enabled="true",
1871
                         uni_a=uni, uni_z=uni)
1872 1
        evc1.name = "name"
1873 1
        evc1.is_affected_by_link.return_value = True
1874 1
        evc1.handle_link_down.return_value = True
1875 1
        evc1.failover_path = None
1876 1
        evc2 = MagicMock(id="2", service_level=6, creation_time=1)
1877 1
        evc2.is_affected_by_link.return_value = False
1878 1
        evc3 = MagicMock(id="3", service_level=5, creation_time=1,
1879
                         metadata="mock", _active="true", _enabled="true",
1880
                         uni_a=uni, uni_z=uni)
1881 1
        evc3.name = "name"
1882 1
        evc3.is_affected_by_link.return_value = True
1883 1
        evc3.handle_link_down.return_value = True
1884 1
        evc3.failover_path = None
1885 1
        evc4 = MagicMock(id="4", service_level=4, creation_time=1,
1886
                         metadata="mock", _active="true", _enabled="true",
1887
                         uni_a=uni, uni_z=uni)
1888 1
        evc4.name = "name"
1889 1
        evc4.is_affected_by_link.return_value = True
1890 1
        evc4.is_failover_path_affected_by_link.return_value = False
1891 1
        evc4.failover_path = ["2"]
1892 1
        evc4.get_failover_flows.return_value = {
1893
            "2": ["flow1", "flow2"],
1894
            "3": ["flow3", "flow4", "flow5", "flow6"],
1895
        }
1896 1
        evc5 = MagicMock(id="5", service_level=7, creation_time=1)
1897 1
        evc5.is_affected_by_link.return_value = True
1898 1
        evc5.is_failover_path_affected_by_link.return_value = False
1899 1
        evc5.failover_path = ["3"]
1900 1
        evc5.get_failover_flows.return_value = {
1901
            "4": ["flow7", "flow8"],
1902
            "5": ["flow9", "flow10"],
1903
        }
1904 1
        evc6 = MagicMock(id="6", service_level=8, creation_time=1,
1905
                         metadata="mock", _active="true", _enabled="true",
1906
                         uni_a=uni, uni_z=uni)
1907 1
        evc6.name = "name"
1908 1
        evc6.is_affected_by_link.return_value = True
1909 1
        evc6.is_failover_path_affected_by_link.return_value = False
1910 1
        evc6.failover_path = ["3"]
1911 1
        evc6.get_failover_flows.side_effect = AttributeError("err")
1912 1
        link = MagicMock(id="123")
1913 1
        event = KytosEvent(name="test", content={"link": link})
1914 1
        self.napp.circuits = {"1": evc1, "2": evc2, "3": evc3, "4": evc4,
1915
                              "5": evc5, "6": evc6}
1916 1
        settings_mock.BATCH_SIZE = 2
1917 1
        self.napp.handle_link_down(event)
1918
1919 1
        assert evc5.service_level > evc4.service_level
1920
        # evc5 batched flows should be sent first
1921 1
        emit_event_mock.assert_has_calls([
1922
            call(
1923
                self.napp.controller,
1924
                context="kytos.flow_manager",
1925
                name="flows.install",
1926
                content={
1927
                    "dpid": "4",
1928
                    "flow_dict": {"flows": ["flow7", "flow8"]},
1929
                }
1930
            ),
1931
            call(
1932
                self.napp.controller,
1933
                context="kytos.flow_manager",
1934
                name="flows.install",
1935
                content={
1936
                    "dpid": "5",
1937
                    "flow_dict": {"flows": ["flow9", "flow10"]},
1938
                }
1939
            ),
1940
            call(
1941
                self.napp.controller,
1942
                context="kytos.flow_manager",
1943
                name="flows.install",
1944
                content={
1945
                    "dpid": "2",
1946
                    "flow_dict": {"flows": ["flow1", "flow2"]},
1947
                }
1948
            ),
1949
            call(
1950
                self.napp.controller,
1951
                context="kytos.flow_manager",
1952
                name="flows.install",
1953
                content={
1954
                    "dpid": "3",
1955
                    "flow_dict": {"flows": ["flow3", "flow4"]},
1956
                }
1957
            ),
1958
            call(
1959
                self.napp.controller,
1960
                context="kytos.flow_manager",
1961
                name="flows.install",
1962
                content={
1963
                    "dpid": "3",
1964
                    "flow_dict": {"flows": ["flow5", "flow6"]},
1965
                }
1966
            ),
1967
        ])
1968 1
        event_name = "evc_affected_by_link_down"
1969 1
        assert evc3.service_level > evc1.service_level
1970
        # evc3 should be handled before evc1
1971 1
        emit_event_mock.assert_has_calls([
1972
            call(self.napp.controller, event_name, content={
1973
                "link_id": "123",
1974
                "evc_id": "6",
1975
                "name": "name",
1976
                "metadata": "mock",
1977
                "active": "true",
1978
                "enabled": "true",
1979
                "uni_a": uni.as_dict(),
1980
                "uni_z": uni.as_dict(),
1981
            }),
1982
            call(self.napp.controller, event_name, content={
1983
                "link_id": "123",
1984
                "evc_id": "3",
1985
                "name": "name",
1986
                "metadata": "mock",
1987
                "active": "true",
1988
                "enabled": "true",
1989
                "uni_a": uni.as_dict(),
1990
                "uni_z": uni.as_dict(),
1991
            }),
1992
            call(self.napp.controller, event_name, content={
1993
                "link_id": "123",
1994
                "evc_id": "1",
1995
                "name": "name",
1996
                "metadata": "mock",
1997
                "active": "true",
1998
                "enabled": "true",
1999
                "uni_a": uni.as_dict(),
2000
                "uni_z": uni.as_dict(),
2001
            }),
2002
        ])
2003 1
        evc4.sync.assert_called_once()
2004 1
        event_name = "redeployed_link_down"
2005 1
        emit_event_mock.assert_has_calls([
2006
            call(self.napp.controller, event_name, content={
2007
                "evc_id": "4",
2008
                "name": "name",
2009
                "metadata": "mock",
2010
                "active": "true",
2011
                "enabled": "true",
2012
                "uni_a": uni.as_dict(),
2013
                "uni_z": uni.as_dict(),
2014
            }),
2015
        ])
2016
2017 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2018 1
    def test_handle_evc_affected_by_link_down(self, emit_event_mock):
2019
        """Test handle_evc_affected_by_link_down method."""
2020 1
        uni = create_autospec(UNI)
2021 1
        evc1 = MagicMock(
2022
            id="1",
2023
            metadata="data_mocked",
2024
            _active="true",
2025
            _enabled="false",
2026
            uni_a=uni,
2027
            uni_z=uni,
2028
        )
2029 1
        evc1.name = "name_mocked"
2030 1
        evc1.handle_link_down.return_value = True
2031 1
        evc2 = MagicMock(
2032
            id="2",
2033
            metadata="mocked_data",
2034
            _active="false",
2035
            _enabled="true",
2036
            uni_a=uni,
2037
            uni_z=uni,
2038
        )
2039 1
        evc2.name = "mocked_name"
2040 1
        evc2.handle_link_down.return_value = False
2041 1
        self.napp.circuits = {"1": evc1, "2": evc2}
2042
2043 1
        event = KytosEvent(name="e1", content={
2044
            "evc_id": "3",
2045
            "link_id": "1",
2046
        })
2047 1
        self.napp.handle_evc_affected_by_link_down(event)
2048 1
        emit_event_mock.assert_not_called()
2049 1
        event.content["evc_id"] = "1"
2050 1
        self.napp.handle_evc_affected_by_link_down(event)
2051 1
        emit_event_mock.assert_called_with(
2052
            self.napp.controller, "redeployed_link_down", content={
2053
                "evc_id": "1",
2054
                "name": "name_mocked",
2055
                "metadata": "data_mocked",
2056
                "active": "true",
2057
                "enabled": "false",
2058
                "uni_a": uni.as_dict(),
2059
                "uni_z": uni.as_dict(),
2060
            }
2061
        )
2062
2063 1
        event.content["evc_id"] = "2"
2064 1
        self.napp.handle_evc_affected_by_link_down(event)
2065 1
        emit_event_mock.assert_called_with(
2066
            self.napp.controller, "error_redeploy_link_down", content={
2067
                "evc_id": "2",
2068
                "name": "mocked_name",
2069
                "metadata": "mocked_data",
2070
                "active": "false",
2071
                "enabled": "true",
2072
                "uni_a": uni.as_dict(),
2073
                "uni_z": uni.as_dict(),
2074
            }
2075
        )
2076
2077 1
    def test_handle_evc_deployed(self):
2078
        """Test handle_evc_deployed method."""
2079 1
        evc = create_autospec(EVC, id="1")
2080 1
        evc.lock = MagicMock()
2081 1
        self.napp.circuits = {"1": evc}
2082
2083 1
        event = KytosEvent(name="e1", content={"evc_id": "2"})
2084 1
        self.napp.handle_evc_deployed(event)
2085 1
        evc.setup_failover_path.assert_not_called()
2086
2087 1
        event.content["evc_id"] = "1"
2088 1
        self.napp.handle_evc_deployed(event)
2089 1
        evc.setup_failover_path.assert_called()
2090
2091 1
    async def test_add_metadata(self, event_loop):
2092
        """Test method to add metadata"""
2093 1
        self.napp.controller.loop = event_loop
2094 1
        evc_mock = create_autospec(EVC)
2095 1
        evc_mock.metadata = {}
2096 1
        evc_mock.id = 1234
2097 1
        self.napp.circuits = {"1234": evc_mock}
2098
2099 1
        payload = {"metadata1": 1, "metadata2": 2}
2100 1
        response = await self.api_client.post(
2101
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2102
            json=payload
2103
        )
2104
2105 1
        assert response.status_code == 201
2106 1
        evc_mock.extend_metadata.assert_called_with(payload)
2107
2108 1
    async def test_add_metadata_malformed_json(self, event_loop):
2109
        """Test method to add metadata with a malformed json"""
2110 1
        self.napp.controller.loop = event_loop
2111 1
        payload = b'{"metadata1": 1, "metadata2": 2,}'
2112 1
        response = await self.api_client.post(
2113
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2114
            content=payload,
2115
            headers={"Content-Type": "application/json"}
2116
        )
2117
2118 1
        assert response.status_code == 400
2119 1
        assert "Failed to deserialize" in response.json()["description"]
2120
2121 1
    async def test_add_metadata_no_body(self, event_loop):
2122
        """Test method to add metadata with no body"""
2123 1
        self.napp.controller.loop = event_loop
2124 1
        response = await self.api_client.post(
2125
            f"{self.base_endpoint}/v2/evc/1234/metadata"
2126
        )
2127 1
        assert response.status_code == 400
2128 1
        assert response.json()["description"] == \
2129
            "Missing required request body"
2130
2131 1
    async def test_add_metadata_no_evc(self, event_loop):
2132
        """Test method to add metadata with no evc"""
2133 1
        self.napp.controller.loop = event_loop
2134 1
        payload = {"metadata1": 1, "metadata2": 2}
2135 1
        response = await self.api_client.post(
2136
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2137
            json=payload,
2138
        )
2139 1
        assert response.status_code == 404
2140 1
        assert response.json()["description"] == \
2141
            "circuit_id 1234 not found."
2142
2143 1
    async def test_add_metadata_wrong_content_type(self, event_loop):
2144
        """Test method to add metadata with wrong content type"""
2145 1
        self.napp.controller.loop = event_loop
2146 1
        payload = {"metadata1": 1, "metadata2": 2}
2147 1
        response = await self.api_client.post(
2148
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2149
            data=payload,
2150
            headers={"Content-Type": "application/xml"}
2151
        )
2152 1
        assert response.status_code == 415
2153 1
        assert "application/xml" in response.json()["description"]
2154
2155 1
    async def test_get_metadata(self):
2156
        """Test method to get metadata"""
2157 1
        evc_mock = create_autospec(EVC)
2158 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2159 1
        evc_mock.id = 1234
2160 1
        self.napp.circuits = {"1234": evc_mock}
2161
2162 1
        response = await self.api_client.get(
2163
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2164
        )
2165 1
        assert response.status_code == 200
2166 1
        assert response.json() == {"metadata": evc_mock.metadata}
2167
2168 1
    async def test_delete_metadata(self):
2169
        """Test method to delete metadata"""
2170 1
        evc_mock = create_autospec(EVC)
2171 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2172 1
        evc_mock.id = 1234
2173 1
        self.napp.circuits = {"1234": evc_mock}
2174
2175 1
        response = await self.api_client.delete(
2176
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2177
        )
2178 1
        assert response.status_code == 200
2179
2180 1
    async def test_delete_metadata_no_evc(self):
2181
        """Test method to delete metadata with no evc"""
2182 1
        response = await self.api_client.delete(
2183
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2184
        )
2185 1
        assert response.status_code == 404
2186 1
        assert response.json()["description"] == \
2187
            "circuit_id 1234 not found."
2188
2189 1
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
2190 1
    def test_load_all_evcs(self, load_evc_mock):
2191
        """Test load_evcs method"""
2192 1
        mock_circuits = {
2193
            'circuits': {
2194
                1: 'circuit_1',
2195
                2: 'circuit_2',
2196
                3: 'circuit_3',
2197
                4: 'circuit_4'
2198
            }
2199
        }
2200 1
        self.napp.mongo_controller.get_circuits.return_value = mock_circuits
2201 1
        self.napp.circuits = {2: 'circuit_2', 3: 'circuit_3'}
2202 1
        self.napp.load_all_evcs()
2203 1
        load_evc_mock.assert_has_calls([call('circuit_1'), call('circuit_4')])
2204 1
        assert self.napp.controller.buffers.app.put.call_count > 1
2205 1
        call_args = self.napp.controller.buffers.app.put.call_args[0]
2206 1
        assert call_args[0].name == "kytos/mef_eline.evcs_loaded"
2207 1
        assert dict(call_args[0].content) == mock_circuits["circuits"]
2208 1
        timeout_d = {"timeout": 1}
2209 1
        assert self.napp.controller.buffers.app.put.call_args[1] == timeout_d
2210
2211 1
    @patch('napps.kytos.mef_eline.main.Main._evc_from_dict')
2212 1
    def test_load_evc(self, evc_from_dict_mock):
2213
        """Test _load_evc method"""
2214
        # pylint: disable=protected-access
2215
        # case 1: early return with ValueError exception
2216 1
        evc_from_dict_mock.side_effect = ValueError("err")
2217 1
        evc_dict = MagicMock()
2218 1
        assert not self.napp._load_evc(evc_dict)
2219
2220
        # case 2: early return with KytosTagError exception
2221 1
        evc_from_dict_mock.side_effect = KytosTagError("")
2222 1
        assert not self.napp._load_evc(evc_dict)
2223
2224
        # case 3: archived evc
2225 1
        evc = MagicMock()
2226 1
        evc.archived = True
2227 1
        evc_from_dict_mock.side_effect = None
2228 1
        evc_from_dict_mock.return_value = evc
2229 1
        assert not self.napp._load_evc(evc_dict)
2230
2231
        # case 4: success creating
2232 1
        evc.archived = False
2233 1
        evc.id = 1
2234 1
        self.napp.sched = MagicMock()
2235
2236 1
        result = self.napp._load_evc(evc_dict)
2237 1
        assert result == evc
2238 1
        self.napp.sched.add.assert_called_with(evc)
2239 1
        assert self.napp.circuits[1] == evc
2240
2241 1
    def test_handle_flow_mod_error(self):
2242
        """Test handle_flow_mod_error method"""
2243 1
        flow = MagicMock()
2244 1
        flow.cookie = 0xaa00000000000011
2245 1
        event = MagicMock()
2246 1
        event.content = {'flow': flow, 'error_command': 'add'}
2247 1
        evc = create_autospec(EVC)
2248 1
        evc.remove_current_flows = MagicMock()
2249 1
        evc.lock = MagicMock()
2250 1
        self.napp.circuits = {"00000000000011": evc}
2251 1
        self.napp.handle_flow_mod_error(event)
2252 1
        evc.remove_current_flows.assert_called_once()
2253
2254 1
    @patch("kytos.core.Controller.get_interface_by_id")
2255 1
    def test_uni_from_dict(self, _get_interface_by_id_mock):
2256
        """Test _uni_from_dict method."""
2257
        # pylint: disable=protected-access
2258
        # case1: early return on empty dict
2259 1
        assert not self.napp._uni_from_dict(None)
2260
2261
        # case2: invalid interface raises ValueError
2262 1
        _get_interface_by_id_mock.return_value = None
2263 1
        uni_dict = {
2264
            "interface_id": "00:01:1",
2265
            "tag": {"tag_type": 'vlan', "value": 81},
2266
        }
2267 1
        with pytest.raises(ValueError):
2268 1
            self.napp._uni_from_dict(uni_dict)
2269
2270
        # case3: success creation
2271 1
        uni_mock = get_uni_mocked(switch_id="00:01")
2272 1
        _get_interface_by_id_mock.return_value = uni_mock.interface
2273 1
        uni = self.napp._uni_from_dict(uni_dict)
2274 1
        assert uni == uni_mock
2275
2276
        # case4: success creation of tag list
2277 1
        uni_dict["tag"]["value"] = [[1, 10]]
2278 1
        uni = self.napp._uni_from_dict(uni_dict)
2279 1
        assert isinstance(uni.user_tag, TAGRange)
2280
2281
        # case5: success creation without tag
2282 1
        uni_mock.user_tag = None
2283 1
        del uni_dict["tag"]
2284 1
        uni = self.napp._uni_from_dict(uni_dict)
2285 1
        assert uni == uni_mock
2286
2287 1
    def test_handle_flow_delete(self):
2288
        """Test handle_flow_delete method"""
2289 1
        flow = MagicMock()
2290 1
        flow.cookie = 0xaa00000000000011
2291 1
        event = MagicMock()
2292 1
        event.content = {'flow': flow}
2293 1
        evc = create_autospec(EVC)
2294 1
        evc.set_flow_removed_at = MagicMock()
2295 1
        self.napp.circuits = {"00000000000011": evc}
2296 1
        self.napp.handle_flow_delete(event)
2297 1
        evc.set_flow_removed_at.assert_called_once()
2298
2299 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...
2300
        """Test add_bulk_metadata method"""
2301 1
        self.napp.controller.loop = event_loop
2302 1
        evc_mock = create_autospec(EVC)
2303 1
        evc_mock.id = 1234
2304 1
        self.napp.circuits = {"1234": evc_mock}
2305 1
        payload = {
2306
            "circuit_ids": ["1234"],
2307
            "metadata1": 1,
2308
            "metadata2": 2
2309
        }
2310 1
        response = await self.api_client.post(
2311
            f"{self.base_endpoint}/v2/evc/metadata",
2312
            json=payload
2313
        )
2314 1
        assert response.status_code == 201
2315 1
        args = self.napp.mongo_controller.update_evcs.call_args[0]
2316 1
        ids = payload.pop("circuit_ids")
2317 1
        assert args[0] == ids
2318 1
        assert args[1] == payload
2319 1
        assert args[2] == "add"
2320 1
        calls = self.napp.mongo_controller.update_evcs.call_count
2321 1
        assert calls == 1
2322 1
        evc_mock.extend_metadata.assert_called_with(payload)
2323
2324 1
    async def test_add_bulk_metadata_empty_list(self, event_loop):
2325
        """Test add_bulk_metadata method empty list"""
2326 1
        self.napp.controller.loop = event_loop
2327 1
        evc_mock = create_autospec(EVC)
2328 1
        evc_mock.id = 1234
2329 1
        self.napp.circuits = {"1234": evc_mock}
2330 1
        payload = {
2331
            "circuit_ids": [],
2332
            "metadata1": 1,
2333
            "metadata2": 2
2334
        }
2335 1
        response = await self.api_client.post(
2336
            f"{self.base_endpoint}/v2/evc/metadata",
2337
            json=payload
2338
        )
2339 1
        assert response.status_code == 400
2340 1
        assert "invalid" in response.json()["description"]
2341
2342 1
    async def test_add_bulk_metadata_no_id(self, event_loop):
2343
        """Test add_bulk_metadata with unknown evc id"""
2344 1
        self.napp.controller.loop = event_loop
2345 1
        evc_mock = create_autospec(EVC)
2346 1
        evc_mock.id = 1234
2347 1
        self.napp.circuits = {"1234": evc_mock}
2348 1
        payload = {
2349
            "circuit_ids": ["1234", "4567"]
2350
        }
2351 1
        response = await self.api_client.post(
2352
            f"{self.base_endpoint}/v2/evc/metadata",
2353
            json=payload
2354
        )
2355 1
        assert response.status_code == 404
2356
2357 1
    async def test_add_bulk_metadata_no_circuits(self, event_loop):
2358
        """Test add_bulk_metadata without circuit_ids"""
2359 1
        self.napp.controller.loop = event_loop
2360 1
        evc_mock = create_autospec(EVC)
2361 1
        evc_mock.id = 1234
2362 1
        self.napp.circuits = {"1234": evc_mock}
2363 1
        payload = {
2364
            "metadata": "data"
2365
        }
2366 1
        response = await self.api_client.post(
2367
            f"{self.base_endpoint}/v2/evc/metadata",
2368
            json=payload
2369
        )
2370 1
        assert response.status_code == 400
2371
2372 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...
2373
        """Test delete_metadata method"""
2374 1
        self.napp.controller.loop = event_loop
2375 1
        evc_mock = create_autospec(EVC)
2376 1
        evc_mock.id = 1234
2377 1
        self.napp.circuits = {"1234": evc_mock}
2378 1
        payload = {
2379
            "circuit_ids": ["1234"]
2380
        }
2381 1
        response = await self.api_client.request(
2382
            "DELETE",
2383
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2384
            json=payload
2385
        )
2386 1
        assert response.status_code == 200
2387 1
        args = self.napp.mongo_controller.update_evcs.call_args[0]
2388 1
        assert args[0] == payload["circuit_ids"]
2389 1
        assert args[1] == {"metadata1": ""}
2390 1
        assert args[2] == "del"
2391 1
        calls = self.napp.mongo_controller.update_evcs.call_count
2392 1
        assert calls == 1
2393 1
        assert evc_mock.remove_metadata.call_count == 1
2394
2395 1
    async def test_delete_bulk_metadata_error(self, event_loop):
2396
        """Test bulk_delete_metadata with ciruit erroring"""
2397 1
        self.napp.controller.loop = event_loop
2398 1
        evc_mock = create_autospec(EVC)
2399 1
        evcs = [evc_mock, evc_mock]
2400 1
        self.napp.circuits = dict(zip(["1", "2"], evcs))
2401 1
        payload = {"circuit_ids": ["1", "2", "3"]}
2402 1
        response = await self.api_client.request(
2403
            "DELETE",
2404
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2405
            json=payload
2406
        )
2407 1
        assert response.status_code == 404, response.data
2408 1
        assert response.json()["description"] == ["3"]
2409
2410 1
    async def test_use_uni_tags(self, event_loop):
2411
        """Test _use_uni_tags"""
2412 1
        self.napp.controller.loop = event_loop
2413 1
        evc_mock = create_autospec(EVC)
2414 1
        evc_mock.uni_a = "uni_a_mock"
2415 1
        evc_mock.uni_z = "uni_z_mock"
2416 1
        self.napp._use_uni_tags(evc_mock)
2417 1
        assert evc_mock._use_uni_vlan.call_count == 2
2418 1
        assert evc_mock._use_uni_vlan.call_args[0][0] == evc_mock.uni_z
2419
2420
        # One UNI tag is not available
2421 1
        evc_mock._use_uni_vlan.side_effect = [KytosTagError(""), None]
2422 1
        with pytest.raises(KytosTagError):
2423 1
            self.napp._use_uni_tags(evc_mock)
2424 1
        assert evc_mock._use_uni_vlan.call_count == 3
2425 1
        assert evc_mock.make_uni_vlan_available.call_count == 0
2426
2427 1
        evc_mock._use_uni_vlan.side_effect = [None, KytosTagError("")]
2428 1
        with pytest.raises(KytosTagError):
2429 1
            self.napp._use_uni_tags(evc_mock)
2430 1
        assert evc_mock._use_uni_vlan.call_count == 5
2431 1
        assert evc_mock.make_uni_vlan_available.call_count == 1
2432
2433 1
    def test_check_no_tag_duplication(self):
2434
        """Test _check_no_tag_duplication"""
2435 1
        evc = MagicMock()
2436 1
        evc.check_no_tag_duplicate = MagicMock()
2437 1
        evc.archived = False
2438 1
        evc.id = "1"
2439 1
        self.napp.circuits = {"1": evc}
2440 1
        evc_id = "2"
2441 1
        uni_a = get_uni_mocked(valid=True)
2442 1
        uni_z = get_uni_mocked(valid=True)
2443 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2444 1
        assert evc.check_no_tag_duplicate.call_count == 0
2445
2446 1
        uni_a.user_tag = None
2447 1
        uni_z.user_tag = None
2448 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2449 1
        assert evc.check_no_tag_duplicate.call_count == 2
2450
2451 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, None)
2452 1
        assert evc.check_no_tag_duplicate.call_count == 3
2453
2454 1
        self.napp._check_no_tag_duplication(evc_id, None, None)
2455 1
        assert evc.check_no_tag_duplicate.call_count == 3
2456
2457 1
    @patch("napps.kytos.mef_eline.main.time")
2458 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_up")
2459 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_down")
2460 1
    def test_handle_on_interface_link_change(
2461
        self,
2462
        mock_down,
2463
        mock_up,
2464
        mock_time
2465
    ):
2466
        """Test handle_on_interface_link_change"""
2467 1
        mock_time.sleep.return_value = True
2468 1
        mock_intf = Mock()
2469 1
        mock_intf.id = "mock_intf"
2470
2471
        # Created/link_up
2472 1
        name = '.*.switch.interface.created'
2473 1
        content = {"interface": mock_intf}
2474 1
        event = KytosEvent(name=name, content=content)
2475 1
        self.napp.handle_on_interface_link_change(event)
2476 1
        assert mock_down.call_count == 0
2477 1
        assert mock_up.call_count == 1
2478
2479
        # Deleted/link_down
2480 1
        name = '.*.switch.interface.deleted'
2481 1
        event = KytosEvent(name=name, content=content)
2482 1
        self.napp.handle_on_interface_link_change(event)
2483 1
        assert mock_down.call_count == 1
2484 1
        assert mock_up.call_count == 1
2485
2486
        # Event delay
2487 1
        self.napp._intf_events[mock_intf.id]["last_acquired"] = "mock_time"
2488 1
        for _ in range(1, 6):
2489 1
            self.napp.handle_on_interface_link_change(event)
2490 1
        assert mock_down.call_count == 1
2491 1
        assert mock_up.call_count == 1
2492
2493 1
        self.napp._intf_events[mock_intf.id].pop("last_acquired")
2494 1
        self.napp.handle_on_interface_link_change(event)
2495 1
        assert mock_down.call_count == 2
2496 1
        assert mock_up.call_count == 1
2497
2498
        # Out of order event
2499 1
        event = KytosEvent(name=name, content=content)
2500 1
        self.napp._intf_events[mock_intf.id]["event"] = Mock(timestamp=now())
2501
2502 1
        self.napp.handle_on_interface_link_change(event)
2503 1
        assert mock_down.call_count == 2
2504
        assert mock_up.call_count == 1
2505