Passed
Pull Request — master (#697)
by
unknown
04:36
created

TestMain.test_update_circuit()   B

Complexity

Conditions 1

Size

Total Lines 135
Code Lines 98

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 45
CRAP Score 1.006

Importance

Changes 0
Metric Value
cc 1
eloc 98
nop 12
dl 0
loc 135
ccs 45
cts 55
cp 0.8182
crap 1.006
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
import asyncio
3 1
from unittest.mock import (AsyncMock, MagicMock, Mock, call,
4
                           create_autospec, patch)
5
6 1
import pytest
7 1
from kytos.lib.helpers import get_controller_mock, get_test_client
8 1
from kytos.core.helpers import now
9 1
from kytos.core.events import KytosEvent
10 1
from kytos.core.exceptions import KytosTagError
11 1
from kytos.core.interface import TAGRange, UNI, Interface
12 1
from napps.kytos.mef_eline.exceptions import FlowModException, InvalidPath
13 1
from napps.kytos.mef_eline.models import EVC, Path
14 1
from napps.kytos.mef_eline.tests.helpers import get_uni_mocked
15
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.controllers.ELineController.upsert_evc")
109 1
    @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_list_traces")
110 1
    def test_execute_consistency(self, mock_check_list_traces, *args):
111
        """Test execute_consistency."""
112 1
        (mongo_controller_upsert_mock, mock_settings) = args
113
114 1
        stored_circuits = {'1': {'name': 'circuit_1'},
115
                           '2': {'name': 'circuit_2'},
116
                           '3': {'name': 'circuit_3'}}
117 1
        mongo_controller_upsert_mock.return_value = True
118 1
        self.napp.mongo_controller.get_circuits.return_value = {
119
            "circuits": stored_circuits
120
        }
121
122 1
        mock_settings.WAIT_FOR_OLD_PATH = -1
123 1
        evc1 = MagicMock(id=1, service_level=0, creation_time=1)
124 1
        evc1.is_enabled.return_value = True
125 1
        evc1.is_active.return_value = False
126 1
        evc1.lock.locked.return_value = False
127 1
        evc1.has_recent_removed_flow.return_value = False
128 1
        evc1.is_recent_updated.return_value = False
129 1
        evc1.execution_rounds = 0
130 1
        evc2 = MagicMock(id=2, service_level=7, creation_time=1)
131 1
        evc2.is_enabled.return_value = True
132 1
        evc2.is_active.return_value = False
133 1
        evc2.lock.locked.return_value = False
134 1
        evc2.has_recent_removed_flow.return_value = False
135 1
        evc2.is_recent_updated.return_value = False
136 1
        evc2.execution_rounds = 0
137 1
        self.napp.circuits = {'1': evc1, '2': evc2}
138 1
        assert self.napp.get_evcs_by_svc_level() == [evc2, evc1]
139
140 1
        mock_check_list_traces.return_value = {
141
                                                1: True,
142
                                                2: False
143
                                            }
144
145 1
        self.napp.execute_consistency()
146 1
        assert evc1.activate.call_count == 1
147 1
        assert evc1.sync.call_count == 1
148 1
        evc1.try_setup_failover_path.assert_called_with(warn_if_not_path=False)
149 1
        assert evc2.deploy.call_count == 1
150 1
        evc2.try_setup_failover_path.assert_called_with(warn_if_not_path=False)
151
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
        expected_result = "circuit_id 3 not found"
407
        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
    ):
430
        """Test create a new circuit."""
431
        # pylint: disable=too-many-locals
432 1
        self.napp.controller.loop = asyncio.get_running_loop()
433 1
        validate_mock.return_value = True
434 1
        mongo_controller_upsert_mock.return_value = True
435 1
        evc_deploy_mock.return_value = True
436 1
        mock_use_uni_tags.return_value = True
437 1
        mock_tags_equal.return_value = True
438 1
        mock_check_duplicate.return_value = True
439 1
        uni1 = create_autospec(UNI)
440 1
        uni2 = create_autospec(UNI)
441 1
        uni1.interface = create_autospec(Interface)
442 1
        uni2.interface = create_autospec(Interface)
443 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
444 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
445 1
        uni_from_dict_mock.side_effect = [uni1, uni2]
446 1
        evc_as_dict_mock.return_value = {}
447 1
        sched_add_mock.return_value = True
448 1
        self.napp.mongo_controller.get_circuits.return_value = {}
449
450 1
        url = f"{self.base_endpoint}/v2/evc/"
451 1
        payload = {
452
            "name": "my evc1",
453
            "frequency": "* * * * *",
454
            "uni_a": {
455
                "interface_id": "00:00:00:00:00:00:00:01:1",
456
                "tag": {"tag_type": 'vlan', "value": 80},
457
            },
458
            "uni_z": {
459
                "interface_id": "00:00:00:00:00:00:00:02:2",
460
                "tag": {"tag_type": 'vlan', "value": 1},
461
            },
462
            "dynamic_backup_path": True,
463
            "primary_constraints": {
464
                "spf_max_path_cost": 8,
465
                "mandatory_metrics": {
466
                    "ownership": "red"
467
                }
468
            },
469
            "secondary_constraints": {
470
                "spf_attribute": "priority",
471
                "mandatory_metrics": {
472
                    "ownership": "blue"
473
                }
474
            }
475
        }
476
477 1
        response = await self.api_client.post(url, json=payload)
478 1
        current_data = response.json()
479
480
        # verify expected result from request
481 1
        assert 201 == response.status_code
482 1
        assert "circuit_id" in current_data
483
484
        # verify uni called
485 1
        uni_from_dict_mock.called_twice()
486 1
        uni_from_dict_mock.assert_any_call(payload["uni_z"])
487 1
        uni_from_dict_mock.assert_any_call(payload["uni_a"])
488
489
        # verify validation called
490 1
        validate_mock.assert_called_once()
491 1
        validate_mock.assert_called_with(
492
            table_group={'evpl': 0, 'epl': 0},
493
            frequency="* * * * *",
494
            name="my evc1",
495
            uni_a=uni1,
496
            uni_z=uni2,
497
            dynamic_backup_path=True,
498
            primary_constraints=payload["primary_constraints"],
499
            secondary_constraints=payload["secondary_constraints"],
500
        )
501
        # verify save method is called
502 1
        mongo_controller_upsert_mock.assert_called_once()
503
504
        # verify evc as dict is called to save in the box
505 1
        evc_as_dict_mock.assert_called()
506
        # verify add circuit in sched
507 1
        sched_add_mock.assert_called_once()
508
509 1
    async def test_create_a_circuit_case_2(self):
510
        """Test create a new circuit trying to send request without a json."""
511 1
        self.napp.controller.loop = asyncio.get_running_loop()
512 1
        url = f"{self.base_endpoint}/v2/evc/"
513
514 1
        response = await self.api_client.post(url)
515
        current_data = response.json()
516
        assert 400 == response.status_code
517
        assert "Missing required request body" in current_data["description"]
518
519 1
    async def test_create_a_circuit_case_3(self):
520
        """Test create a new circuit trying to send request with an
521
        invalid json."""
522 1
        self.napp.controller.loop = asyncio.get_running_loop()
523 1
        url = f"{self.base_endpoint}/v2/evc/"
524
525 1
        response = await self.api_client.post(
526
            url,
527
            json="This is an {Invalid:} JSON",
528
        )
529
        current_data = response.json()
530
        assert 400 == response.status_code
531
        assert "This is an {Invalid:" in current_data["description"]
532
533 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
534 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
535 1
    async def test_create_a_circuit_case_4(
536
        self,
537
        mongo_controller_upsert_mock,
538
        uni_from_dict_mock
539
    ):
540
        """Test create a new circuit trying to send request with an
541
        invalid value."""
542 1
        self.napp.controller.loop = asyncio.get_running_loop()
543
        # pylint: disable=too-many-locals
544 1
        uni_from_dict_mock.side_effect = ValueError("Could not instantiate")
545 1
        mongo_controller_upsert_mock.return_value = True
546 1
        url = f"{self.base_endpoint}/v2/evc/"
547
548 1
        payload = {
549
            "name": "my evc1",
550
            "frequency": "* * * * *",
551
            "uni_a": {
552
                "interface_id": "00:00:00:00:00:00:00:01:76",
553
                "tag": {"tag_type": 'vlan', "value": 80},
554
            },
555
            "uni_z": {
556
                "interface_id": "00:00:00:00:00:00:00:02:2",
557
                "tag": {"tag_type": 'vlan', "value": 1},
558
            },
559
        }
560
561 1
        response = await self.api_client.post(url, json=payload)
562
        current_data = response.json()
563
        expected_data = "Error creating UNI: Invalid value"
564
        assert 400 == response.status_code
565
        assert current_data["description"] == expected_data
566
567
        payload["name"] = 1
568
        response = await self.api_client.post(url, json=payload)
569
        assert 400 == response.status_code, response.data
570
571 1
    async def test_create_a_circuit_invalid_queue_id(self):
572
        """Test create a new circuit with invalid queue_id."""
573 1
        self.napp.controller.loop = asyncio.get_running_loop()
574 1
        url = f"{self.base_endpoint}/v2/evc/"
575
576 1
        payload = {
577
            "name": "my evc1",
578
            "queue_id": 8,
579
            "uni_a": {
580
                "interface_id": "00:00:00:00:00:00:00:01:76",
581
                "tag": {"tag_type": 'vlan', "value": 80},
582
            },
583
            "uni_z": {
584
                "interface_id": "00:00:00:00:00:00:00:02:2",
585
                "tag": {"tag_type": 'vlan', "value": 1},
586
            },
587
        }
588 1
        response = await self.api_client.post(url, json=payload)
589
        current_data = response.json()
590
        expected_data = "8 is greater than the maximum of 7"
591
592
        assert response.status_code == 400
593
        assert expected_data in current_data["description"]
594
595 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
596 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
597 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
598 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
599 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
600 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
601 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
602 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
603 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
604 1
    async def test_create_circuit_already_enabled(
605
        self,
606
        evc_as_dict_mock,
607
        validate_mock,
608
        mongo_controller_upsert_mock,
609
        uni_from_dict_mock,
610
        sched_add_mock,
611
        evc_deploy_mock,
612
        mock_use_uni_tags,
613
        mock_tags_equal,
614
        mock_check_duplicate
615
    ):
616
        """Test create an already created circuit."""
617
        # pylint: disable=too-many-locals
618 1
        self.napp.controller.loop = asyncio.get_running_loop()
619 1
        validate_mock.return_value = True
620 1
        mongo_controller_upsert_mock.return_value = True
621 1
        sched_add_mock.return_value = True
622 1
        evc_deploy_mock.return_value = True
623 1
        mock_tags_equal.return_value = True
624 1
        mock_check_duplicate.return_value = True
625 1
        mock_use_uni_tags.side_effect = [
626
            None, KytosTagError("The EVC already exists.")
627
        ]
628 1
        uni1 = create_autospec(UNI)
629 1
        uni2 = create_autospec(UNI)
630 1
        uni1.interface = create_autospec(Interface)
631 1
        uni2.interface = create_autospec(Interface)
632 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
633 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
634 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
635
636 1
        payload = {
637
            "name": "my evc1",
638
            "uni_a": {
639
                "interface_id": "00:00:00:00:00:00:00:01:1",
640
                "tag": {"tag_type": 'vlan', "value": 80},
641
            },
642
            "uni_z": {
643
                "interface_id": "00:00:00:00:00:00:00:02:2",
644
                "tag": {"tag_type": 'vlan', "value": 1},
645
            },
646
            "dynamic_backup_path": True,
647
        }
648
649 1
        evc_as_dict_mock.return_value = payload
650 1
        response = await self.api_client.post(
651
            f"{self.base_endpoint}/v2/evc/",
652
            json=payload
653
        )
654 1
        assert 201 == response.status_code
655
656 1
        response = await self.api_client.post(
657
            f"{self.base_endpoint}/v2/evc/",
658
            json=payload
659
        )
660
        current_data = response.json()
661
        expected_data = "The EVC already exists."
662
        assert current_data["description"] == expected_data
663
        assert 400 == response.status_code
664
665 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
666 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
667 1
    async def test_create_circuit_case_5(
668
        self,
669
        uni_from_dict_mock,
670
        mock_tags_equal
671
    ):
672
        """Test when neither primary path nor dynamic_backup_path is set."""
673 1
        self.napp.controller.loop = asyncio.get_running_loop()
674 1
        mock_tags_equal.return_value = True
675 1
        url = f"{self.base_endpoint}/v2/evc/"
676 1
        uni1 = create_autospec(UNI)
677 1
        uni2 = create_autospec(UNI)
678 1
        uni1.interface = create_autospec(Interface)
679 1
        uni2.interface = create_autospec(Interface)
680 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
681 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
682 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
683
684 1
        payload = {
685
            "name": "my evc1",
686
            "frequency": "* * * * *",
687
            "uni_a": {
688
                "interface_id": "00:00:00:00:00:00:00:01:1",
689
                "tag": {"tag_type": 'vlan', "value": 80},
690
            },
691
            "uni_z": {
692
                "interface_id": "00:00:00:00:00:00:00:02:2",
693
                "tag": {"tag_type": 'vlan', "value": 1},
694
            },
695
        }
696
697 1
        response = await self.api_client.post(url, json=payload)
698
        current_data = response.json()
699
        expected_data = "The EVC must have a primary path "
700
        expected_data += "or allow dynamic paths."
701
        assert 400 == response.status_code, response.data
702
        assert current_data["description"] == expected_data
703
704 1
    @patch("napps.kytos.mef_eline.main.Main._evc_from_dict")
705 1
    async def test_create_circuit_case_6(self, mock_evc):
706
        """Test create_circuit with KytosTagError"""
707 1
        self.napp.controller.loop = asyncio.get_running_loop()
708 1
        url = f"{self.base_endpoint}/v2/evc/"
709 1
        mock_evc.side_effect = KytosTagError("")
710 1
        payload = {
711
            "name": "my evc1",
712
            "uni_a": {
713
                "interface_id": "00:00:00:00:00:00:00:01:1",
714
            },
715
            "uni_z": {
716
                "interface_id": "00:00:00:00:00:00:00:02:2",
717
            },
718
        }
719 1
        response = await self.api_client.post(url, json=payload)
720
        assert response.status_code == 400, response.data
721
722 1
    async def test_redeploy_evc(self):
723
        """Test endpoint to redeploy an EVC."""
724 1
        evc1 = MagicMock()
725 1
        evc1.is_enabled.return_value = True
726 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
727 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
728 1
        response = await self.api_client.patch(url)
729 1
        evc1.remove_failover_flows.assert_called()
730 1
        evc1.remove_current_flows.assert_called_with(
731
            sync=False, return_path=True
732
        )
733 1
        assert response.status_code == 202, response.data
734
735 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
736 1
        url = url + "?try_avoid_same_s_vlan=false"
737 1
        response = await self.api_client.patch(url)
738 1
        evc1.remove_current_flows.assert_called_with(
739
            sync=False, return_path=False
740
        )
741
742 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
743 1
        url = url + "?try_avoid_same_s_vlan=True"
744 1
        response = await self.api_client.patch(url)
745 1
        evc1.remove_current_flows.assert_called_with(
746
            sync=False, return_path=True
747
        )
748
749 1
    async def test_redeploy_evc_disabled(self):
750
        """Test endpoint to redeploy an EVC."""
751 1
        evc1 = MagicMock()
752 1
        evc1.is_enabled.return_value = False
753 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
754 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
755 1
        response = await self.api_client.patch(url)
756 1
        evc1.remove_failover_flows.assert_not_called()
757 1
        evc1.remove_current_flows.assert_not_called()
758 1
        assert response.status_code == 409, response.data
759
760 1
    async def test_redeploy_evc_deleted(self):
761
        """Test endpoint to redeploy an EVC."""
762 1
        evc1 = MagicMock()
763 1
        evc1.is_enabled.return_value = True
764 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
765 1
        url = f"{self.base_endpoint}/v2/evc/3/redeploy"
766 1
        response = await self.api_client.patch(url)
767
        assert response.status_code == 404, response.data
768
769 1
    async def test_list_schedules__no_data_stored(self):
770
        """Test if list circuits return all circuits stored."""
771 1
        self.napp.mongo_controller.get_circuits.return_value = {"circuits": {}}
772
773 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
774
775 1
        response = await self.api_client.get(url)
776 1
        assert response.status_code == 200
777 1
        assert not response.json()
778
779 1
    def _add_mongodb_schedule_data(self, data_mock):
780
        """Add schedule data to mongodb mock object."""
781 1
        circuits = {"circuits": {}}
782 1
        payload_1 = {
783
            "id": "aa:aa:aa",
784
            "name": "my evc1",
785
            "uni_a": {
786
                "interface_id": "00:00:00:00:00:00:00:01:1",
787
                "tag": {"tag_type": 'vlan', "value": 80},
788
            },
789
            "uni_z": {
790
                "interface_id": "00:00:00:00:00:00:00:02:2",
791
                "tag": {"tag_type": 'vlan', "value": 1},
792
            },
793
            "circuit_scheduler": [
794
                {"id": "1", "frequency": "* * * * *", "action": "create"},
795
                {"id": "2", "frequency": "1 * * * *", "action": "remove"},
796
            ],
797
        }
798 1
        circuits["circuits"].update({"aa:aa:aa": payload_1})
799 1
        payload_2 = {
800
            "id": "bb:bb:bb",
801
            "name": "my second evc2",
802
            "uni_a": {
803
                "interface_id": "00:00:00:00:00:00:00:01:2",
804
                "tag": {"tag_type": 'vlan', "value": 90},
805
            },
806
            "uni_z": {
807
                "interface_id": "00:00:00:00:00:00:00:03:2",
808
                "tag": {"tag_type": 'vlan', "value": 100},
809
            },
810
            "circuit_scheduler": [
811
                {"id": "3", "frequency": "1 * * * *", "action": "create"},
812
                {"id": "4", "frequency": "2 * * * *", "action": "remove"},
813
            ],
814
        }
815 1
        circuits["circuits"].update({"bb:bb:bb": payload_2})
816 1
        payload_3 = {
817
            "id": "cc:cc:cc",
818
            "name": "my third evc3",
819
            "uni_a": {
820
                "interface_id": "00:00:00:00:00:00:00:03:1",
821
                "tag": {"tag_type": 'vlan', "value": 90},
822
            },
823
            "uni_z": {
824
                "interface_id": "00:00:00:00:00:00:00:04:2",
825
                "tag": {"tag_type": 'vlan', "value": 100},
826
            },
827
        }
828 1
        circuits["circuits"].update({"cc:cc:cc": payload_3})
829
        # Add one circuit to the mongodb.
830 1
        data_mock.return_value = circuits
831
832 1
    async def test_list_schedules_from_mongodb(self):
833
        """Test if list circuits return specific circuits stored."""
834 1
        self._add_mongodb_schedule_data(
835
            self.napp.mongo_controller.get_circuits
836
        )
837
838 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
839
840
        # Call URL
841 1
        response = await self.api_client.get(url)
842
        # Expected JSON data from response
843 1
        expected = [
844
            {
845
                "circuit_id": "aa:aa:aa",
846
                "schedule": {
847
                    "action": "create",
848
                    "frequency": "* * * * *",
849
                    "id": "1",
850
                },
851
                "schedule_id": "1",
852
            },
853
            {
854
                "circuit_id": "aa:aa:aa",
855
                "schedule": {
856
                    "action": "remove",
857
                    "frequency": "1 * * * *",
858
                    "id": "2",
859
                },
860
                "schedule_id": "2",
861
            },
862
            {
863
                "circuit_id": "bb:bb:bb",
864
                "schedule": {
865
                    "action": "create",
866
                    "frequency": "1 * * * *",
867
                    "id": "3",
868
                },
869
                "schedule_id": "3",
870
            },
871
            {
872
                "circuit_id": "bb:bb:bb",
873
                "schedule": {
874
                    "action": "remove",
875
                    "frequency": "2 * * * *",
876
                    "id": "4",
877
                },
878
                "schedule_id": "4",
879
            },
880
        ]
881
882 1
        assert response.status_code == 200
883 1
        assert expected == response.json()
884
885 1
    async def test_get_specific_schedule_from_mongodb(self):
886
        """Test get schedules from a circuit."""
887 1
        self._add_mongodb_schedule_data(
888
            self.napp.mongo_controller.get_circuits
889
        )
890
891 1
        requested_circuit_id = "bb:bb:bb"
892 1
        evc = self.napp.mongo_controller.get_circuits()
893 1
        evc = evc["circuits"][requested_circuit_id]
894 1
        self.napp.mongo_controller.get_circuit.return_value = evc
895 1
        url = f"{self.base_endpoint}/v2/evc/{requested_circuit_id}"
896
897
        # Call URL
898 1
        response = await self.api_client.get(url)
899
900
        # Expected JSON data from response
901 1
        expected = [
902
            {"action": "create", "frequency": "1 * * * *", "id": "3"},
903
            {"action": "remove", "frequency": "2 * * * *", "id": "4"},
904
        ]
905
906 1
        assert response.status_code == 200
907 1
        assert expected == response.json()["circuit_scheduler"]
908
909 1
    async def test_get_specific_schedules_from_mongodb_not_found(self):
910
        """Test get specific schedule ID that does not exist."""
911 1
        requested_id = "blah"
912 1
        self.napp.mongo_controller.get_circuit.return_value = None
913 1
        url = f"{self.base_endpoint}/v2/evc/{requested_id}"
914
915
        # Call URL
916 1
        response = await self.api_client.get(url)
917
918
        expected = "circuit_id blah not found"
919
        # Assert response not found
920
        assert response.status_code == 404
921
        assert expected == response.json()["description"]
922
923 1
    def _uni_from_dict_side_effect(self, uni_dict):
924 1
        interface_id = uni_dict.get("interface_id")
925 1
        tag_dict = uni_dict.get("tag")
926 1
        interface = Interface(interface_id, "0", MagicMock(id="1"))
927 1
        return UNI(interface, tag_dict)
928
929 1
    @patch("apscheduler.schedulers.background.BackgroundScheduler.add_job")
930 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
931 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
932 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
933 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
934 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
935 1
    async def test_create_schedule(
936
        self,
937
        validate_mock,
938
        evc_as_dict_mock,
939
        mongo_controller_upsert_mock,
940
        uni_from_dict_mock,
941
        sched_add_mock,
942
        scheduler_add_job_mock
943
    ):
944
        """Test create a circuit schedule."""
945 1
        self.napp.controller.loop = asyncio.get_running_loop()
946 1
        validate_mock.return_value = True
947 1
        mongo_controller_upsert_mock.return_value = True
948 1
        uni_from_dict_mock.side_effect = self._uni_from_dict_side_effect
949 1
        evc_as_dict_mock.return_value = {}
950 1
        sched_add_mock.return_value = True
951
952 1
        self._add_mongodb_schedule_data(
953
            self.napp.mongo_controller.get_circuits
954
        )
955
956 1
        requested_id = "bb:bb:bb"
957 1
        url = f"{self.base_endpoint}/v2/evc/schedule/"
958
959 1
        payload = {
960
            "circuit_id": requested_id,
961
            "schedule": {"frequency": "1 * * * *", "action": "create"},
962
            "metadata": {"metadata1": "test_data"},
963
        }
964
965
        # Call URL
966 1
        response = await self.api_client.post(url, json=payload)
967 1
        response_json = response.json()
968
969 1
        assert response.status_code == 201
970 1
        scheduler_add_job_mock.assert_called_once()
971 1
        mongo_controller_upsert_mock.assert_called_once()
972 1
        assert payload["schedule"]["frequency"] == response_json["frequency"]
973 1
        assert payload["schedule"]["action"] == response_json["action"]
974 1
        assert response_json["id"] is not None
975
976
        # Case 2: there is no schedule
977 1
        payload = {
978
              "circuit_id": "cc:cc:cc",
979
              "schedule": {
980
                "frequency": "1 * * * *",
981
                "action": "create"
982
              }
983
            }
984 1
        response = await self.api_client.post(url, json=payload)
985 1
        assert response.status_code == 201
986
987 1
    async def test_create_schedule_invalid_request(self):
988
        """Test create schedule API with invalid request."""
989 1
        self.napp.controller.loop = asyncio.get_running_loop()
990 1
        evc1 = MagicMock()
991 1
        self.napp.circuits = {'bb:bb:bb': evc1}
992 1
        url = f'{self.base_endpoint}/v2/evc/schedule/'
993
994
        # case 1: empty post
995 1
        response = await self.api_client.post(url, json={})
996
        assert response.status_code == 400
997
998
        # case 2: not a dictionary
999
        payload = []
1000
        response = await self.api_client.post(url, json=payload)
1001
        assert response.status_code == 400
1002
1003
        # case 3: missing circuit id
1004
        payload = {
1005
            "schedule": {
1006
                "frequency": "1 * * * *",
1007
                "action": "create"
1008
            }
1009
        }
1010
        response = await self.api_client.post(url, json=payload)
1011
        assert response.status_code == 400
1012
1013
        # case 4: missing schedule
1014
        payload = {
1015
            "circuit_id": "bb:bb:bb"
1016
        }
1017
        response = await self.api_client.post(url, json=payload)
1018
        assert response.status_code == 400
1019
1020
        # case 5: invalid circuit
1021
        payload = {
1022
            "circuit_id": "xx:xx:xx",
1023
            "schedule": {
1024
                "frequency": "1 * * * *",
1025
                "action": "create"
1026
            }
1027
        }
1028
        response = await self.api_client.post(url, json=payload)
1029
        assert response.status_code == 404
1030
1031
        # case 6: invalid json
1032
        response = await self.api_client.post(url, json="test")
1033
        assert response.status_code == 400
1034
1035 1
    @patch('apscheduler.schedulers.background.BackgroundScheduler.remove_job')
1036 1
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1037 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1038 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1039 1
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1040 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1041 1
    async def test_update_schedule(
1042
        self,
1043
        validate_mock,
1044
        evc_as_dict_mock,
1045
        mongo_controller_upsert_mock,
1046
        uni_from_dict_mock,
1047
        sched_add_mock,
1048
        scheduler_remove_job_mock
1049
    ):
1050
        """Test create a circuit schedule."""
1051 1
        self.napp.controller.loop = asyncio.get_running_loop()
1052 1
        mongo_payload_1 = {
1053
            "circuits": {
1054
                "aa:aa:aa": {
1055
                    "id": "aa:aa:aa",
1056
                    "name": "my evc1",
1057
                    "uni_a": {
1058
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1059
                        "tag": {"tag_type": 'vlan', "value": 80},
1060
                    },
1061
                    "uni_z": {
1062
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1063
                        "tag": {"tag_type": 'vlan', "value": 1},
1064
                    },
1065
                    "circuit_scheduler": [
1066
                        {
1067
                            "id": "1",
1068
                            "frequency": "* * * * *",
1069
                            "action": "create"
1070
                        }
1071
                    ],
1072
                }
1073
            }
1074
        }
1075
1076 1
        validate_mock.return_value = True
1077 1
        mongo_controller_upsert_mock.return_value = True
1078 1
        sched_add_mock.return_value = True
1079 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1080 1
        evc_as_dict_mock.return_value = {}
1081 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1082 1
        scheduler_remove_job_mock.return_value = True
1083
1084 1
        requested_schedule_id = "1"
1085 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1086
1087 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1088
1089
        # Call URL
1090 1
        response = await self.api_client.patch(url, json=payload)
1091 1
        response_json = response.json()
1092
1093 1
        assert response.status_code == 200
1094 1
        scheduler_remove_job_mock.assert_called_once()
1095 1
        mongo_controller_upsert_mock.assert_called_once()
1096 1
        assert payload["frequency"] == response_json["frequency"]
1097 1
        assert payload["action"] == response_json["action"]
1098 1
        assert response_json["id"] is not None
1099
1100 1
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1101 1
    async def test_update_no_schedule(
1102
        self, find_evc_by_schedule_id_mock
1103
    ):
1104
        """Test update a circuit schedule."""
1105 1
        self.napp.controller.loop = asyncio.get_running_loop()
1106 1
        url = f"{self.base_endpoint}/v2/evc/schedule/1"
1107 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1108
1109 1
        find_evc_by_schedule_id_mock.return_value = None, None
1110
1111 1
        response = await self.api_client.patch(url, json=payload)
1112
        assert response.status_code == 404
1113
1114 1
    @patch("apscheduler.schedulers.background.BackgroundScheduler.remove_job")
1115 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1116 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1117 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1118 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1119 1
    async def test_delete_schedule(self, *args):
1120
        """Test create a circuit schedule."""
1121 1
        (
1122
            validate_mock,
1123
            evc_as_dict_mock,
1124
            mongo_controller_upsert_mock,
1125
            uni_from_dict_mock,
1126
            scheduler_remove_job_mock,
1127
        ) = args
1128
1129 1
        mongo_payload_1 = {
1130
            "circuits": {
1131
                "2": {
1132
                    "id": "2",
1133
                    "name": "my evc1",
1134
                    "uni_a": {
1135
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1136
                        "tag": {"tag_type": 'vlan', "value": 80},
1137
                    },
1138
                    "uni_z": {
1139
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1140
                        "tag": {"tag_type": 'vlan', "value": 1},
1141
                    },
1142
                    "circuit_scheduler": [
1143
                        {
1144
                            "id": "1",
1145
                            "frequency": "* * * * *",
1146
                            "action": "create"
1147
                        }
1148
                    ],
1149
                }
1150
            }
1151
        }
1152 1
        validate_mock.return_value = True
1153 1
        mongo_controller_upsert_mock.return_value = True
1154 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1155 1
        evc_as_dict_mock.return_value = {}
1156 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1157 1
        scheduler_remove_job_mock.return_value = True
1158
1159 1
        requested_schedule_id = "1"
1160 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1161
1162
        # Call URL
1163 1
        response = await self.api_client.delete(url)
1164
1165 1
        assert response.status_code == 200
1166 1
        scheduler_remove_job_mock.assert_called_once()
1167 1
        mongo_controller_upsert_mock.assert_called_once()
1168 1
        assert "Schedule removed" in f"{response.json()}"
1169
1170 1
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1171 1
    async def test_delete_schedule_not_found(self, mock_find_evc_by_sched):
1172
        """Test delete a circuit schedule - unexisting."""
1173 1
        mock_find_evc_by_sched.return_value = (None, False)
1174 1
        url = f'{self.base_endpoint}/v2/evc/schedule/1'
1175 1
        response = await self.api_client.delete(url)
1176
        assert response.status_code == 404
1177
1178 1
    def test_get_evcs_by_svc_level(self) -> None:
1179
        """Test get_evcs_by_svc_level."""
1180 1
        levels = [1, 2, 4, 2, 7]
1181 1
        evcs = {i: MagicMock(service_level=v, creation_time=1)
1182
                for i, v in enumerate(levels)}
1183 1
        self.napp.circuits = evcs
1184 1
        expected_levels = sorted(levels, reverse=True)
1185 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1186 1
        assert evcs_by_level
1187
1188 1
        for evc, exp_level in zip(evcs_by_level, expected_levels):
1189 1
            assert evc.service_level == exp_level
1190
1191 1
        evcs = {i: MagicMock(service_level=1, creation_time=i)
1192
                for i in reversed(range(2))}
1193 1
        self.napp.circuits = evcs
1194 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1195 1
        for i in range(2):
1196 1
            assert evcs_by_level[i].creation_time == i
1197
1198 1
        self.napp.circuits[1].is_enabled = lambda: False
1199 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1200 1
        assert len(evcs_by_level) == 1
1201
1202 1
        self.napp.circuits[1].is_enabled = lambda: False
1203 1
        evcs_by_level = self.napp.get_evcs_by_svc_level(enable_filter=False)
1204 1
        assert len(evcs_by_level) == 2
1205
1206 1
    async def test_get_circuit_not_found(self):
1207
        """Test /v2/evc/<circuit_id> 404."""
1208 1
        self.napp.mongo_controller.get_circuit.return_value = None
1209 1
        url = f'{self.base_endpoint}/v2/evc/1234'
1210 1
        response = await self.api_client.get(url)
1211
        assert response.status_code == 404
1212
1213 1
    @patch('httpx.post')
1214 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1215 1
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1216 1
    @patch('napps.kytos.mef_eline.controllers.ELineController.update_evc')
1217 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1218 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1219 1
    @patch('kytos.core.Controller.get_interface_by_id')
1220 1
    @patch('napps.kytos.mef_eline.models.path.Path.is_valid')
1221 1
    @patch('napps.kytos.mef_eline.models.evc.EVCDeploy.deploy')
1222 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1223 1
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1224 1
    async def test_update_circuit(
1225
        self,
1226
        evc_as_dict_mock,
1227
        uni_from_dict_mock,
1228
        evc_deploy,
1229
        _is_valid_mock,
1230
        interface_by_id_mock,
1231
        _mock_validate,
1232
        _mongo_controller_upsert_mock,
1233
        _mongo_controller_update_mock,
1234
        _sched_add_mock,
1235
        mock_use_uni_tags,
1236
        httpx_mock
1237
    ):
1238
        """Test update a circuit circuit."""
1239 1
        self.napp.controller.loop = asyncio.get_running_loop()
1240 1
        mock_use_uni_tags.return_value = True
1241 1
        evc_deploy.return_value = True
1242 1
        interface_by_id_mock.return_value = get_uni_mocked().interface
1243 1
        unis = [
1244
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:01"),
1245
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:02"),
1246
        ]
1247 1
        uni_from_dict_mock.side_effect = 2 * unis
1248
1249 1
        response = MagicMock()
1250 1
        response.status_code = 201
1251 1
        httpx_mock.return_value = response
1252
1253 1
        payloads = [
1254
            {
1255
                "name": "my evc1",
1256
                "uni_a": {
1257
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1258
                    "tag": {"tag_type": 'vlan', "value": 80},
1259
                },
1260
                "uni_z": {
1261
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1262
                    "tag": {"tag_type": 'vlan', "value": 1},
1263
                },
1264
                "dynamic_backup_path": True,
1265
            },
1266
            {
1267
                "primary_path": [
1268
                    {
1269
                        "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1270
                        "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1271
                    }
1272
                ]
1273
            },
1274
            {
1275
                "sb_priority": 3
1276
            },
1277
            {
1278
                # It works only with 'enabled' and not with 'enable'
1279
                "enabled": True
1280
            },
1281
            {
1282
                "sb_priority": 100
1283
            }
1284
        ]
1285
1286 1
        evc_as_dict_mock.return_value = payloads[0]
1287 1
        response = await self.api_client.post(
1288
            f"{self.base_endpoint}/v2/evc/",
1289
            json=payloads[0],
1290
        )
1291 1
        assert 201 == response.status_code
1292
1293 1
        evc_deploy.reset_mock()
1294 1
        evc_as_dict_mock.return_value = payloads[1]
1295 1
        current_data = response.json()
1296 1
        circuit_id = current_data["circuit_id"]
1297 1
        response = await self.api_client.patch(
1298
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1299
            json=payloads[1],
1300
        )
1301
        # evc_deploy.assert_called_once()
1302 1
        assert 200 == response.status_code
1303
1304 1
        evc_deploy.reset_mock()
1305 1
        evc_as_dict_mock.return_value = payloads[2]
1306 1
        response = await self.api_client.patch(
1307
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1308
            json=payloads[2],
1309
        )
1310 1
        evc_deploy.assert_not_called()
1311 1
        assert 200 == response.status_code
1312
1313 1
        evc_deploy.reset_mock()
1314 1
        evc_as_dict_mock.return_value = payloads[3]
1315 1
        response = await self.api_client.patch(
1316
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1317
            json=payloads[3],
1318
        )
1319 1
        evc_deploy.assert_called_once()
1320 1
        assert 200 == response.status_code
1321
1322 1
        evc_deploy.reset_mock()
1323 1
        response = await self.api_client.patch(
1324
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1325
            content=b'{"priority":5,}',
1326
            headers={"Content-Type": "application/json"}
1327
        )
1328
        evc_deploy.assert_not_called()
1329
        assert 400 == response.status_code
1330
1331
        response = await self.api_client.patch(
1332
            f"{self.base_endpoint}/v2/evc/1234",
1333
            json=payloads[1],
1334
        )
1335
        current_data = response.json()
1336
        expected_data = "circuit_id 1234 not found"
1337
        assert current_data["description"] == expected_data
1338
        assert 404 == response.status_code
1339
1340
        self.napp.circuits[circuit_id]._active = False
1341
        evc_deploy.reset_mock()
1342
        response = await self.api_client.patch(
1343
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1344
            json=payloads[4]
1345
        )
1346 1
        assert 200 == response.status_code
1347 1
        evc_deploy.assert_called_once()
1348
1349 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...
1350 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1351 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1352 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1353 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1354 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1355 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1356 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1357 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1358 1
    async def test_update_circuit_invalid_json(
1359
        self,
1360
        evc_as_dict_mock,
1361
        validate_mock,
1362
        mongo_controller_upsert_mock,
1363
        uni_from_dict_mock,
1364
        sched_add_mock,
1365
        evc_deploy_mock,
1366
        mock_use_uni_tags,
1367
        mock_tags_equal,
1368
        mock_check_duplicate
1369
    ):
1370
        """Test update a circuit circuit."""
1371 1
        self.napp.controller.loop = asyncio.get_running_loop()
1372 1
        validate_mock.return_value = True
1373 1
        mongo_controller_upsert_mock.return_value = True
1374 1
        sched_add_mock.return_value = True
1375 1
        evc_deploy_mock.return_value = True
1376 1
        mock_use_uni_tags.return_value = True
1377 1
        mock_tags_equal.return_value = True
1378 1
        mock_check_duplicate.return_value = True
1379 1
        uni1 = create_autospec(UNI)
1380 1
        uni2 = create_autospec(UNI)
1381 1
        uni1.interface = create_autospec(Interface)
1382 1
        uni2.interface = create_autospec(Interface)
1383 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1384 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1385 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1386
1387 1
        payload1 = {
1388
            "name": "my evc1",
1389
            "uni_a": {
1390
                "interface_id": "00:00:00:00:00:00:00:01:1",
1391
                "tag": {"tag_type": 'vlan', "value": 80},
1392
            },
1393
            "uni_z": {
1394
                "interface_id": "00:00:00:00:00:00:00:02:2",
1395
                "tag": {"tag_type": 'vlan', "value": 1},
1396
            },
1397
            "dynamic_backup_path": True,
1398
        }
1399
1400 1
        payload2 = {
1401
            "dynamic_backup_path": False,
1402
        }
1403
1404 1
        evc_as_dict_mock.return_value = payload1
1405 1
        response = await self.api_client.post(
1406
            f"{self.base_endpoint}/v2/evc/",
1407
            json=payload1
1408
        )
1409 1
        assert 201 == response.status_code
1410
1411 1
        evc_as_dict_mock.return_value = payload2
1412 1
        current_data = response.json()
1413 1
        circuit_id = current_data["circuit_id"]
1414 1
        response = await self.api_client.patch(
1415
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1416
            json=payload2
1417
        )
1418
        current_data = response.json()
1419
        assert 400 == response.status_code
1420
        assert "must have a primary path or" in current_data["description"]
1421
1422 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
1423 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1424 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1425 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1426 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1427 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1428 1
    @patch("napps.kytos.mef_eline.main.Main._link_from_dict")
1429 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1430 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1431 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1432 1
    @patch("napps.kytos.mef_eline.models.path.Path.is_valid")
1433 1
    async def test_update_circuit_invalid_path(
1434
        self,
1435
        is_valid_mock,
1436
        evc_as_dict_mock,
1437
        validate_mock,
1438
        mongo_controller_upsert_mock,
1439
        link_from_dict_mock,
1440
        uni_from_dict_mock,
1441
        sched_add_mock,
1442
        evc_deploy_mock,
1443
        mock_use_uni_tags,
1444
        mock_tags_equal,
1445
        mock_check_duplicate
1446
    ):
1447
        """Test update a circuit circuit."""
1448 1
        self.napp.controller.loop = asyncio.get_running_loop()
1449 1
        is_valid_mock.side_effect = InvalidPath("error")
1450 1
        validate_mock.return_value = True
1451 1
        mongo_controller_upsert_mock.return_value = True
1452 1
        sched_add_mock.return_value = True
1453 1
        evc_deploy_mock.return_value = True
1454 1
        mock_use_uni_tags.return_value = True
1455 1
        link_from_dict_mock.return_value = 1
1456 1
        mock_tags_equal.return_value = True
1457 1
        mock_check_duplicate.return_value = True
1458 1
        uni1 = create_autospec(UNI)
1459 1
        uni2 = create_autospec(UNI)
1460 1
        uni1.interface = create_autospec(Interface)
1461 1
        uni2.interface = create_autospec(Interface)
1462 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1463 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1464 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1465
1466 1
        payload1 = {
1467
            "name": "my evc1",
1468
            "uni_a": {
1469
                "interface_id": "00:00:00:00:00:00:00:01:1",
1470
                "tag": {"tag_type": 'vlan', "value": 80},
1471
            },
1472
            "uni_z": {
1473
                "interface_id": "00:00:00:00:00:00:00:02:2",
1474
                "tag": {"tag_type": 'vlan', "value": 1},
1475
            },
1476
            "dynamic_backup_path": True,
1477
        }
1478
1479 1
        payload2 = {
1480
            "primary_path": [
1481
                {
1482
                    "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1483
                    "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1484
                }
1485
            ]
1486
        }
1487
1488 1
        evc_as_dict_mock.return_value = payload1
1489 1
        response = await self.api_client.post(
1490
            f"{self.base_endpoint}/v2/evc/",
1491
            json=payload1,
1492
        )
1493 1
        assert 201 == response.status_code
1494
1495 1
        evc_as_dict_mock.return_value = payload2
1496 1
        current_data = response.json()
1497 1
        circuit_id = current_data["circuit_id"]
1498 1
        response = await self.api_client.patch(
1499
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1500
            json=payload2,
1501
        )
1502
        current_data = response.json()
1503
        expected_data = "primary_path is not a valid path: error"
1504
        assert 400 == response.status_code
1505
        assert current_data["description"] == expected_data
1506
1507 1
    def test_link_from_dict_non_existent_intf(self):
1508
        """Test _link_from_dict non existent intf."""
1509 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1510 1
        link_dict = {
1511
            "endpoint_a": {"id": "a"},
1512
            "endpoint_b": {"id": "b"}
1513
        }
1514 1
        with pytest.raises(ValueError):
1515 1
            self.napp._link_from_dict(link_dict, "current_path")
1516
1517 1
    def test_link_from_dict_vlan_metadata(self):
1518
        """Test that link_from_dict only accepts vlans for current_path
1519
         and failover_path."""
1520 1
        intf = MagicMock(id="01:1")
1521 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=intf)
1522 1
        link_dict = {
1523
            'id': 'mock_link',
1524
            'endpoint_a': {'id': '00:00:00:00:00:00:00:01:4'},
1525
            'endpoint_b': {'id': '00:00:00:00:00:00:00:05:2'},
1526
            'metadata': {'s_vlan': {'tag_type': 'vlan', 'value': 1}}
1527
        }
1528 1
        link = self.napp._link_from_dict(link_dict, "current_path")
1529 1
        assert link.metadata.get('s_vlan', None)
1530
1531 1
        link = self.napp._link_from_dict(link_dict, "failover_path")
1532 1
        assert link.metadata.get('s_vlan', None)
1533
1534 1
        link = self.napp._link_from_dict(link_dict, "primary_path")
1535 1
        assert link.metadata.get('s_vlan', None) is None
1536
1537 1
    def test_uni_from_dict_non_existent_intf(self):
1538
        """Test _link_from_dict non existent intf."""
1539 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1540 1
        uni_dict = {
1541
            "interface_id": "aaa",
1542
        }
1543 1
        with pytest.raises(ValueError):
1544 1
            self.napp._uni_from_dict(uni_dict)
1545
1546 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...
1547 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1548 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1549 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1550 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1551 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1552 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1553 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1554 1
    async def test_update_evc_no_json_mime(
1555
        self,
1556
        mongo_controller_upsert_mock,
1557
        validate_mock,
1558
        uni_from_dict_mock,
1559
        sched_add_mock,
1560
        evc_deploy_mock,
1561
        mock_use_uni_tags,
1562
        mock_tags_equal,
1563
        mock_check_duplicate
1564
    ):
1565
        """Test update a circuit with wrong mimetype."""
1566 1
        self.napp.controller.loop = asyncio.get_running_loop()
1567 1
        validate_mock.return_value = True
1568 1
        sched_add_mock.return_value = True
1569 1
        evc_deploy_mock.return_value = True
1570 1
        mock_use_uni_tags.return_value = True
1571 1
        mock_tags_equal.return_value = True
1572 1
        mock_check_duplicate.return_value = True
1573 1
        uni1 = create_autospec(UNI)
1574 1
        uni2 = create_autospec(UNI)
1575 1
        uni1.interface = create_autospec(Interface)
1576 1
        uni2.interface = create_autospec(Interface)
1577 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1578 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1579 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1580 1
        mongo_controller_upsert_mock.return_value = True
1581
1582 1
        payload1 = {
1583
            "name": "my evc1",
1584
            "uni_a": {
1585
                "interface_id": "00:00:00:00:00:00:00:01:1",
1586
                "tag": {"tag_type": 'vlan', "value": 80},
1587
            },
1588
            "uni_z": {
1589
                "interface_id": "00:00:00:00:00:00:00:02:2",
1590
                "tag": {"tag_type": 'vlan', "value": 1},
1591
            },
1592
            "dynamic_backup_path": True,
1593
        }
1594
1595 1
        payload2 = {"dynamic_backup_path": False}
1596
1597 1
        response = await self.api_client.post(
1598
            f"{self.base_endpoint}/v2/evc/",
1599
            json=payload1,
1600
        )
1601 1
        assert 201 == response.status_code
1602
1603 1
        current_data = response.json()
1604 1
        circuit_id = current_data["circuit_id"]
1605 1
        response = await self.api_client.patch(
1606
            f"{self.base_endpoint}/v2/evc/{circuit_id}", data=payload2
1607
        )
1608
        current_data = response.json()
1609
        assert 415 == response.status_code
1610
        assert "application/json" in current_data["description"]
1611
1612 1
    async def test_delete_no_evc(self):
1613
        """Test delete when EVC does not exist."""
1614 1
        url = f"{self.base_endpoint}/v2/evc/123"
1615 1
        response = await self.api_client.delete(url)
1616
        current_data = response.json()
1617
        expected_data = "circuit_id 123 not found"
1618
        assert current_data["description"] == expected_data
1619
        assert 404 == response.status_code
1620
1621 1
    @patch("napps.kytos.mef_eline.main.Main._check_no_tag_duplication")
1622 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._tag_lists_equal")
1623 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_uni_tags")
1624 1
    @patch("napps.kytos.mef_eline.main.Main._use_uni_tags")
1625 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_current_flows")
1626 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1627 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1628 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1629 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1630 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1631 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1632 1
    async def test_delete_archived_evc(
1633
        self,
1634
        evc_as_dict_mock,
1635
        validate_mock,
1636
        mongo_controller_upsert_mock,
1637
        uni_from_dict_mock,
1638
        sched_add_mock,
1639
        evc_deploy_mock,
1640
        remove_current_flows_mock,
1641
        mock_use_uni,
1642
        mock_remove_tags,
1643
        mock_tags_equal,
1644
        mock_check_duplicate
1645
    ):
1646
        """Try to delete an archived EVC"""
1647 1
        self.napp.controller.loop = asyncio.get_running_loop()
1648 1
        validate_mock.return_value = True
1649 1
        mongo_controller_upsert_mock.return_value = True
1650 1
        sched_add_mock.return_value = True
1651 1
        evc_deploy_mock.return_value = True
1652 1
        mock_use_uni.return_value = True
1653 1
        mock_tags_equal.return_value = True
1654 1
        mock_check_duplicate.return_value = True
1655 1
        uni1 = create_autospec(UNI)
1656 1
        uni2 = create_autospec(UNI)
1657 1
        uni1.interface = create_autospec(Interface)
1658 1
        uni2.interface = create_autospec(Interface)
1659 1
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1660 1
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1661 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1662
1663 1
        payload1 = {
1664
            "name": "my evc1",
1665
            "uni_a": {
1666
                "interface_id": "00:00:00:00:00:00:00:01:1",
1667
                "tag": {"tag_type": 'vlan', "value": 80},
1668
            },
1669
            "uni_z": {
1670
                "interface_id": "00:00:00:00:00:00:00:02:2",
1671
                "tag": {"tag_type": 'vlan', "value": 1},
1672
            },
1673
            "dynamic_backup_path": True,
1674
        }
1675
1676 1
        evc_as_dict_mock.return_value = payload1
1677 1
        response = await self.api_client.post(
1678
            f"{self.base_endpoint}/v2/evc/",
1679
            json=payload1
1680
        )
1681 1
        assert 201 == response.status_code
1682 1
        assert len(self.napp.circuits) == 1
1683 1
        current_data = response.json()
1684 1
        circuit_id = current_data["circuit_id"]
1685 1
        self.napp.circuits[circuit_id].archive()
1686
1687 1
        response = await self.api_client.delete(
1688
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1689
        )
1690 1
        assert 200 == response.status_code
1691 1
        assert mock_remove_tags.call_count == 0
1692 1
        assert remove_current_flows_mock.call_count == 0
1693 1
        assert len(self.napp.circuits) == 0
1694
1695 1
        response = await self.api_client.delete(
1696
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1697
        )
1698
        current_data = response.json()
1699
        expected_data = f"circuit_id {circuit_id} not found"
1700
        assert current_data["description"] == expected_data
1701
        assert 404 == response.status_code
1702
        assert len(self.napp.circuits) == 0
1703
1704 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1705 1
    async def test_delete_circuit(self, emit_event_mock):
1706
        """Test delete_circuit"""
1707 1
        evc = MagicMock()
1708 1
        evc.archived = False
1709 1
        circuit_id = '1'
1710 1
        self.napp.circuits[circuit_id] = evc
1711 1
        response = await self.api_client.delete(
1712
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1713
        )
1714 1
        assert 200 == response.status_code
1715 1
        assert evc.deactivate.call_count == 1
1716 1
        assert evc.disable.call_count == 1
1717 1
        evc.remove_current_flows.assert_called_once_with(
1718
            sync=False
1719
        )
1720 1
        evc.remove_failover_flows.assert_called_once_with(
1721
            sync=False
1722
        )
1723 1
        assert evc.archive.call_count == 1
1724 1
        assert evc.remove_uni_tags.call_count == 1
1725 1
        assert evc.sync.call_count == 1
1726 1
        assert not self.napp.circuits
1727 1
        assert emit_event_mock.call_count == 1
1728
1729 1
    def test_handle_link_up(self):
1730
        """Test handle_link_up method."""
1731 1
        evc_mock = create_autospec(EVC)
1732 1
        evc_mock.service_level, evc_mock.creation_time = 0, 1
1733 1
        evc_mock.is_enabled = MagicMock(side_effect=[
1734
            True, False, True, True, True
1735
        ])
1736 1
        evc_mock.lock = MagicMock()
1737 1
        evc_mock.archived = False
1738 1
        evcs = [evc_mock, evc_mock, evc_mock]
1739 1
        event = KytosEvent(name="test", content={"link": "abc"})
1740 1
        self.napp.circuits = dict(zip(["1", "2", "3"], evcs))
1741 1
        self.napp.handle_link_up(event)
1742 1
        assert evc_mock.handle_link_up.call_count == 2
1743 1
        evc_mock.handle_link_up.assert_called_with("abc")
1744
1745 1
    def test_handle_link_down(
1746
        self
1747
    ):
1748
        """Test handle_link_down method."""
1749 1
        evc1 = MagicMock(id="1")
1750 1
        evc1.is_affected_by_link.return_value = True
1751 1
        evc1.is_failover_path_affected_by_link.return_value = True
1752
1753 1
        evc2 = MagicMock(id="2")
1754 1
        evc2.is_affected_by_link.return_value = True
1755 1
        evc2.failover_path = Path([])
1756
1757 1
        default_undeploy = [evc1, evc2]
1758
1759 1
        evc3 = MagicMock(id="3")
1760 1
        evc3.is_affected_by_link.return_value = True
1761 1
        evc3.is_failover_path_affected_by_link.return_value = False
1762
1763 1
        evc4 = MagicMock(id="4")
1764 1
        evc4.is_affected_by_link.return_value = True
1765 1
        evc4.is_failover_path_affected_by_link.return_value = False
1766
1767 1
        default_swap_to_failover = [evc3, evc4]
1768
1769 1
        evc5 = MagicMock(id="5")
1770 1
        evc5.is_affected_by_link.return_value = False
1771 1
        evc5.is_failover_path_affected_by_link.return_value = True
1772
1773 1
        evc6 = MagicMock(id="6")
1774 1
        evc6.is_affected_by_link.return_value = False
1775 1
        evc6.is_failover_path_affected_by_link.return_value = True
1776
1777 1
        default_clear_failover = [evc5, evc6]
1778
1779 1
        self.napp.get_evcs_by_svc_level = MagicMock()
1780
1781 1
        self.napp.get_evcs_by_svc_level.return_value = [
1782
            evc1,
1783
            evc2,
1784
            evc3,
1785
            evc4,
1786
            evc5,
1787
            evc6,
1788
        ]
1789
1790 1
        self.napp.execute_swap_to_failover = MagicMock()
1791
1792 1
        swap_to_failover_success = [evc3]
1793 1
        swap_to_failover_failure = [evc4]
1794
1795 1
        self.napp.execute_swap_to_failover.return_value =\
1796
            swap_to_failover_success, swap_to_failover_failure
1797
1798 1
        self.napp.execute_clear_failover = MagicMock()
1799
1800 1
        clear_failover_success = [evc5, evc3]
1801 1
        clear_failover_failure = [evc6]
1802
1803 1
        self.napp.execute_clear_failover.return_value =\
1804
            clear_failover_success, clear_failover_failure
1805
1806 1
        self.napp.execute_undeploy = MagicMock()
1807
1808 1
        undeploy_success = [evc1, evc4, evc6]
1809 1
        undeploy_failure = [evc2]
1810
1811 1
        self.napp.execute_undeploy.return_value =\
1812
            undeploy_success, undeploy_failure
1813
1814 1
        link = MagicMock(id="123")
1815 1
        event = KytosEvent(name="test", content={"link": link})
1816
1817 1
        self.napp.handle_link_down(event)
1818
1819 1
        self.napp.execute_swap_to_failover.assert_called_with(
1820
            default_swap_to_failover
1821
        )
1822
1823 1
        self.napp.execute_clear_failover.assert_called_with(
1824
            [*default_clear_failover, *swap_to_failover_success]
1825
        )
1826
1827 1
        self.napp.execute_undeploy.assert_called_with([
1828
            *default_undeploy,
1829
            *swap_to_failover_failure,
1830
            *clear_failover_failure
1831
        ])
1832
1833 1
        self.napp.mongo_controller.update_evcs.assert_called_with([
1834
            evc3.as_dict(),
1835
            evc5.as_dict(),
1836
            evc1.as_dict(),
1837
            evc4.as_dict(),
1838
            evc6.as_dict(),
1839
        ])
1840
1841 1 View Code Duplication
    @patch("napps.kytos.mef_eline.main.emit_event")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1842 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
1843 1
    def test_execute_swap_to_failover(
1844
        self,
1845
        send_flow_mods_mock: MagicMock,
1846
        emit_main_mock: MagicMock,
1847
    ):
1848
        """Test execute_swap_to_failover method."""
1849 1
        evc1 = MagicMock(id="1")
1850 1
        good_path = MagicMock(id="GoodPath")
1851 1
        bad_path = MagicMock(id="BadPath")
1852 1
        evc1.current_path = bad_path
1853 1
        evc1.failover_path = good_path
1854 1
        evc2 = MagicMock(id="2")
1855
1856 1
        self.napp.prepare_swap_to_failover_flow = {
1857
            evc1: {"1": ["Flow1"]},
1858
            evc2: None
1859
        }.get
1860
1861 1
        self.napp.prepare_swap_to_failover_event = {
1862
            evc1: "FailoverEvent1",
1863
        }.get
1864
1865 1
        success, failure = self.napp.execute_swap_to_failover([evc1, evc2])
1866
1867 1
        assert success == [evc1]
1868 1
        assert failure == [evc2]
1869
1870 1
        send_flow_mods_mock.assert_called_with(
1871
            {"1": ["Flow1"]},
1872
            "install"
1873
        )
1874
1875 1
        assert evc1.current_path == good_path
1876 1
        assert evc1.failover_path == bad_path
1877
1878 1
        emit_main_mock.assert_called_with(
1879
            self.napp.controller,
1880
            "failover_link_down",
1881
            content={"1": "FailoverEvent1"}
1882
        )
1883
1884 1 View Code Duplication
    @patch("napps.kytos.mef_eline.main.emit_event")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1885 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
1886 1
    def test_execute_swap_to_failover_exception(
1887
        self,
1888
        send_flow_mods_mock: MagicMock,
1889
        emit_main_mock: MagicMock,
1890
    ):
1891
        """Test handle_link_down method when an exception occurs."""
1892 1
        evc1 = MagicMock(id="1")
1893 1
        good_path = MagicMock(id="GoodPath")
1894 1
        bad_path = MagicMock(id="BadPath")
1895 1
        evc1.current_path = bad_path
1896 1
        evc1.failover_path = good_path
1897 1
        evc2 = MagicMock(id="2")
1898
1899 1
        self.napp.prepare_swap_to_failover_flow = {
1900
            evc1: {"1": ["Flow1"]},
1901
            evc2: None
1902
        }.get
1903
1904 1
        self.napp.prepare_swap_to_failover_event = {
1905
            evc1: "FailoverEvent1",
1906
        }.get
1907
1908 1
        send_flow_mods_mock.side_effect = FlowModException(
1909
            "Flowmod failed to send"
1910
        )
1911
1912 1
        success, failure = self.napp.execute_swap_to_failover([evc1, evc2])
1913
1914 1
        assert success == []
1915 1
        assert failure == [evc1, evc2]
1916
1917 1
        send_flow_mods_mock.assert_called_with(
1918
            {"1": ["Flow1"]},
1919
            "install"
1920
        )
1921
1922 1
        assert evc1.current_path == bad_path
1923 1
        assert evc1.failover_path == good_path
1924
1925 1
        emit_main_mock.assert_not_called()
1926
1927 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1928 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
1929 1
    def test_execute_clear_failover(
1930
        self,
1931
        send_flow_mods_mock: MagicMock,
1932
        emit_main_mock: MagicMock,
1933
    ):
1934
        """Test execute_clear_failover method."""
1935 1
        evc1 = MagicMock(id="1")
1936 1
        good_path = MagicMock(id="GoodPath")
1937 1
        bad_path = MagicMock(id="BadPath")
1938 1
        evc1.current_path = good_path
1939 1
        evc1.failover_path = bad_path
1940 1
        evc2 = MagicMock(id="2")
1941
1942 1
        self.napp.prepare_clear_failover_flow = {
1943
            evc1: {"1": ["Flow1"]},
1944
            evc2: None
1945
        }.get
1946
1947 1
        self.napp.prepare_clear_failover_event = {
1948
            evc1: "FailoverEvent1",
1949
        }.get
1950
1951 1
        success, failure = self.napp.execute_clear_failover([evc1, evc2])
1952
1953 1
        assert success == [evc1]
1954 1
        assert failure == [evc2]
1955
1956 1
        send_flow_mods_mock.assert_called_with(
1957
            {"1": ["Flow1"]},
1958
            "delete"
1959
        )
1960
1961 1
        assert evc1.current_path == good_path
1962 1
        assert not evc1.failover_path
1963
1964 1
        bad_path.make_vlans_available.assert_called_once_with(
1965
            self.napp.controller
1966
        )
1967
1968 1
        emit_main_mock.assert_called_with(
1969
            self.napp.controller,
1970
            "failover_old_path",
1971
            content={"1": "FailoverEvent1"}
1972
        )
1973
1974 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1975 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
1976 1
    def test_execute_clear_failover_exception(
1977
        self,
1978
        send_flow_mods_mock: MagicMock,
1979
        emit_main_mock: MagicMock,
1980
    ):
1981
        """Test execute_clear_failover method when an exception occurs."""
1982 1
        evc1 = MagicMock(id="1")
1983 1
        good_path = MagicMock(id="GoodPath")
1984 1
        bad_path = MagicMock(id="BadPath")
1985 1
        evc1.current_path = good_path
1986 1
        evc1.failover_path = bad_path
1987 1
        evc2 = MagicMock(id="2")
1988
1989 1
        self.napp.prepare_clear_failover_flow = {
1990
            evc1: {"1": ["Flow1"]},
1991
            evc2: None
1992
        }.get
1993
1994 1
        self.napp.prepare_clear_failover_event = {
1995
            evc1: "FailoverEvent1",
1996
        }.get
1997
1998 1
        send_flow_mods_mock.side_effect = FlowModException(
1999
            "Flowmod failed to send"
2000
        )
2001
2002 1
        success, failure = self.napp.execute_clear_failover([evc1, evc2])
2003
2004 1
        assert success == []
2005 1
        assert failure == [evc1, evc2]
2006
2007 1
        send_flow_mods_mock.assert_called_with(
2008
            {"1": ["Flow1"]},
2009
            "delete"
2010
        )
2011
2012 1
        assert evc1.current_path == good_path
2013 1
        assert evc1.failover_path == bad_path
2014
2015 1
        emit_main_mock.assert_not_called()
2016
2017 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2018 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2019 1
    def test_execute_undeploy(
2020
        self,
2021
        send_flow_mods_mock: MagicMock,
2022
        emit_main_mock: MagicMock,
2023
    ):
2024
        """Test execute_undeploy method."""
2025 1
        evc1 = MagicMock(id="1")
2026 1
        bad_path1 = MagicMock(id="GoodPath")
2027 1
        bad_path2 = MagicMock(id="BadPath")
2028 1
        evc1.current_path = bad_path1
2029 1
        evc1.failover_path = bad_path2
2030 1
        evc2 = MagicMock(id="2")
2031
2032 1
        self.napp.prepare_undeploy_flow = {
2033
            evc1: {"1": ["Flow1"]},
2034
            evc2: None
2035
        }.get
2036
2037 1
        success, failure = self.napp.execute_undeploy([evc1, evc2])
2038
2039 1
        assert success == [evc1]
2040 1
        assert failure == [evc2]
2041
2042 1
        send_flow_mods_mock.assert_called_with(
2043
            {"1": ["Flow1"]},
2044
            "delete"
2045
        )
2046
2047 1
        assert not evc1.current_path
2048 1
        assert not evc1.failover_path
2049
2050 1
        assert evc2.current_path
2051 1
        assert evc2.failover_path
2052
2053 1
        bad_path1.make_vlans_available.assert_called_once_with(
2054
            self.napp.controller
2055
        )
2056 1
        bad_path2.make_vlans_available.assert_called_once_with(
2057
            self.napp.controller
2058
        )
2059
2060 1
        evc1.deactivate.assert_called()
2061 1
        evc2.deactivate.assert_not_called()
2062
2063 1
        emit_main_mock.assert_called_with(
2064
            self.napp.controller,
2065
            "need_redeploy",
2066
            content={"evc_id": "1"}
2067
        )
2068
2069 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2070 1
    @patch("napps.kytos.mef_eline.main.send_flow_mods_http")
2071 1
    def test_execute_undeploy_exception(
2072
        self,
2073
        send_flow_mods_mock: MagicMock,
2074
        emit_main_mock: MagicMock,
2075
    ):
2076
        """Test execute_undeploy method method when an exception occurs."""
2077 1
        evc1 = MagicMock(id="1")
2078 1
        bad_path1 = MagicMock(id="GoodPath")
2079 1
        bad_path2 = MagicMock(id="BadPath")
2080 1
        evc1.current_path = bad_path1
2081 1
        evc1.failover_path = bad_path2
2082 1
        evc2 = MagicMock(id="2")
2083
2084 1
        self.napp.prepare_undeploy_flow = {
2085
            evc1: {"1": ["Flow1"]},
2086
            evc2: None
2087
        }.get
2088
2089 1
        send_flow_mods_mock.side_effect = FlowModException(
2090
            "Flowmod failed to send"
2091
        )
2092
2093 1
        success, failure = self.napp.execute_undeploy([evc1, evc2])
2094
2095 1
        assert success == []
2096 1
        assert failure == [evc1, evc2]
2097
2098 1
        send_flow_mods_mock.assert_called_with(
2099
            {"1": ["Flow1"]},
2100
            "delete"
2101
        )
2102
2103 1
        assert evc1.current_path
2104 1
        assert evc1.failover_path
2105
2106 1
        assert evc2.current_path
2107 1
        assert evc2.failover_path
2108
2109 1
        bad_path1.make_vlans_available.assert_not_called()
2110 1
        bad_path2.make_vlans_available.assert_not_called()
2111
2112 1
        evc1.deactivate.assert_not_called()
2113 1
        evc2.deactivate.assert_not_called()
2114
2115 1
        emit_main_mock.assert_not_called()
2116
2117 1
    @patch("napps.kytos.mef_eline.main.emit_event")
2118 1
    def test_handle_evc_affected_by_link_down(self, emit_event_mock):
2119
        """Test handle_evc_affected_by_link_down method."""
2120 1
        uni = create_autospec(UNI)
2121 1
        evc1 = MagicMock(
2122
            id="1",
2123
            metadata="data_mocked",
2124
            _active="true",
2125
            _enabled="false",
2126
            uni_a=uni,
2127
            uni_z=uni,
2128
        )
2129 1
        evc1.name = "name_mocked"
2130 1
        evc1.handle_link_down.return_value = True
2131 1
        evc2 = MagicMock(
2132
            id="2",
2133
            metadata="mocked_data",
2134
            _active="false",
2135
            _enabled="true",
2136
            uni_a=uni,
2137
            uni_z=uni,
2138
        )
2139 1
        evc2.name = "mocked_name"
2140 1
        evc2.handle_link_down.return_value = False
2141 1
        self.napp.circuits = {"1": evc1, "2": evc2}
2142
2143 1
        event = KytosEvent(name="e1", content={
2144
            "evc_id": "3",
2145
            "link": MagicMock(),
2146
        })
2147 1
        self.napp.handle_evc_affected_by_link_down(event)
2148 1
        emit_event_mock.assert_not_called()
2149 1
        event.content["evc_id"] = "1"
2150 1
        self.napp.handle_evc_affected_by_link_down(event)
2151 1
        emit_event_mock.assert_called_with(
2152
            self.napp.controller, "redeployed_link_down", content={
2153
                "id": "1",
2154
                "evc_id": "1",
2155
                "name": "name_mocked",
2156
                "metadata": "data_mocked",
2157
                "active": "true",
2158
                "enabled": "false",
2159
                "uni_a": uni.as_dict(),
2160
                "uni_z": uni.as_dict(),
2161
            }
2162
        )
2163
2164 1
        event.content["evc_id"] = "2"
2165 1
        self.napp.handle_evc_affected_by_link_down(event)
2166 1
        emit_event_mock.assert_called_with(
2167
            self.napp.controller, "error_redeploy_link_down", content={
2168
                "evc_id": "2",
2169
                "id": "2",
2170
                "name": "mocked_name",
2171
                "metadata": "mocked_data",
2172
                "active": "false",
2173
                "enabled": "true",
2174
                "uni_a": uni.as_dict(),
2175
                "uni_z": uni.as_dict(),
2176
            }
2177
        )
2178
2179 1
    async def test_add_metadata(self):
2180
        """Test method to add metadata"""
2181 1
        self.napp.controller.loop = asyncio.get_running_loop()
2182 1
        evc_mock = create_autospec(EVC)
2183 1
        evc_mock.metadata = {}
2184 1
        evc_mock.id = 1234
2185 1
        self.napp.circuits = {"1234": evc_mock}
2186
2187 1
        payload = {"metadata1": 1, "metadata2": 2}
2188 1
        response = await self.api_client.post(
2189
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2190
            json=payload
2191
        )
2192
2193 1
        assert response.status_code == 201
2194 1
        evc_mock.extend_metadata.assert_called_with(payload)
2195
2196 1
    async def test_add_metadata_malformed_json(self):
2197
        """Test method to add metadata with a malformed json"""
2198 1
        self.napp.controller.loop = asyncio.get_running_loop()
2199 1
        payload = b'{"metadata1": 1, "metadata2": 2,}'
2200 1
        response = await self.api_client.post(
2201
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2202
            content=payload,
2203
            headers={"Content-Type": "application/json"}
2204
        )
2205
2206
        assert response.status_code == 400
2207
        assert "body contains invalid API" in response.json()["description"]
2208
2209 1
    async def test_add_metadata_no_body(self):
2210
        """Test method to add metadata with no body"""
2211 1
        self.napp.controller.loop = asyncio.get_running_loop()
2212 1
        response = await self.api_client.post(
2213
            f"{self.base_endpoint}/v2/evc/1234/metadata"
2214
        )
2215
        assert response.status_code == 400
2216
        assert response.json()["description"] == \
2217
            "Missing required request body"
2218
2219 1
    async def test_add_metadata_no_evc(self):
2220
        """Test method to add metadata with no evc"""
2221 1
        self.napp.controller.loop = asyncio.get_running_loop()
2222 1
        payload = {"metadata1": 1, "metadata2": 2}
2223 1
        response = await self.api_client.post(
2224
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2225
            json=payload,
2226
        )
2227
        assert response.status_code == 404
2228
        assert response.json()["description"] == \
2229
            "circuit_id 1234 not found."
2230
2231 1
    async def test_add_metadata_wrong_content_type(self):
2232
        """Test method to add metadata with wrong content type"""
2233 1
        self.napp.controller.loop = asyncio.get_running_loop()
2234 1
        payload = {"metadata1": 1, "metadata2": 2}
2235 1
        response = await self.api_client.post(
2236
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2237
            data=payload,
2238
            headers={"Content-Type": "application/xml"}
2239
        )
2240
        assert response.status_code == 415
2241
        assert "application/xml" in response.json()["description"]
2242
2243 1
    async def test_get_metadata(self):
2244
        """Test method to get metadata"""
2245 1
        evc_mock = create_autospec(EVC)
2246 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2247 1
        evc_mock.id = 1234
2248 1
        self.napp.circuits = {"1234": evc_mock}
2249
2250 1
        response = await self.api_client.get(
2251
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2252
        )
2253 1
        assert response.status_code == 200
2254 1
        assert response.json() == {"metadata": evc_mock.metadata}
2255
2256 1
    async def test_delete_metadata(self):
2257
        """Test method to delete metadata"""
2258 1
        evc_mock = create_autospec(EVC)
2259 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2260 1
        evc_mock.id = 1234
2261 1
        self.napp.circuits = {"1234": evc_mock}
2262
2263 1
        response = await self.api_client.delete(
2264
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2265
        )
2266 1
        assert response.status_code == 200
2267
2268 1
    async def test_delete_metadata_no_evc(self):
2269
        """Test method to delete metadata with no evc"""
2270 1
        response = await self.api_client.delete(
2271
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2272
        )
2273
        assert response.status_code == 404
2274
        assert response.json()["description"] == \
2275
            "circuit_id 1234 not found."
2276
2277 1
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
2278 1
    def test_load_all_evcs(self, load_evc_mock):
2279
        """Test load_evcs method"""
2280 1
        mock_circuits = {
2281
            'circuits': {
2282
                1: 'circuit_1',
2283
                2: 'circuit_2',
2284
                3: 'circuit_3',
2285
                4: 'circuit_4'
2286
            }
2287
        }
2288 1
        self.napp.mongo_controller.get_circuits.return_value = mock_circuits
2289 1
        self.napp.circuits = {2: 'circuit_2', 3: 'circuit_3'}
2290 1
        self.napp.load_all_evcs()
2291 1
        load_evc_mock.assert_has_calls([call('circuit_1'), call('circuit_4')])
2292 1
        assert self.napp.controller.buffers.app.put.call_count > 1
2293 1
        call_args = self.napp.controller.buffers.app.put.call_args[0]
2294 1
        assert call_args[0].name == "kytos/mef_eline.evcs_loaded"
2295 1
        assert dict(call_args[0].content) == mock_circuits["circuits"]
2296 1
        timeout_d = {"timeout": 1}
2297 1
        assert self.napp.controller.buffers.app.put.call_args[1] == timeout_d
2298
2299 1
    @patch('napps.kytos.mef_eline.main.Main._evc_from_dict')
2300 1
    def test_load_evc(self, evc_from_dict_mock):
2301
        """Test _load_evc method"""
2302
        # pylint: disable=protected-access
2303
        # case 1: early return with ValueError exception
2304 1
        evc_from_dict_mock.side_effect = ValueError("err")
2305 1
        evc_dict = MagicMock()
2306 1
        assert not self.napp._load_evc(evc_dict)
2307
2308
        # case 2: early return with KytosTagError exception
2309 1
        evc_from_dict_mock.side_effect = KytosTagError("")
2310 1
        assert not self.napp._load_evc(evc_dict)
2311
2312
        # case 3: archived evc
2313 1
        evc = MagicMock()
2314 1
        evc.archived = True
2315 1
        evc_from_dict_mock.side_effect = None
2316 1
        evc_from_dict_mock.return_value = evc
2317 1
        assert not self.napp._load_evc(evc_dict)
2318
2319
        # case 4: success creating
2320 1
        evc.archived = False
2321 1
        evc.id = 1
2322 1
        self.napp.sched = MagicMock()
2323
2324 1
        result = self.napp._load_evc(evc_dict)
2325 1
        assert result == evc
2326 1
        self.napp.sched.add.assert_called_with(evc)
2327 1
        assert self.napp.circuits[1] == evc
2328
2329 1
    def test_handle_flow_mod_error(self):
2330
        """Test handle_flow_mod_error method"""
2331 1
        flow = MagicMock()
2332 1
        flow.cookie = 0xaa00000000000011
2333 1
        event = MagicMock()
2334 1
        event.content = {'flow': flow, 'error_command': 'add'}
2335 1
        evc = create_autospec(EVC)
2336 1
        evc.archived = False
2337 1
        evc.remove_current_flows = MagicMock()
2338 1
        evc.lock = MagicMock()
2339 1
        self.napp.circuits = {"00000000000011": evc}
2340 1
        self.napp.handle_flow_mod_error(event)
2341 1
        evc.remove_current_flows.assert_called_once()
2342
2343 1
    def test_handle_flow_mod_error_return(self):
2344
        """Test handle_flow_mod_error method with early return."""
2345 1
        flow = MagicMock()
2346 1
        flow.cookie = 0xaa00000000000011
2347 1
        event = MagicMock()
2348 1
        event.content = {'flow': flow, 'error_command': 'delete'}
2349
2350 1
        evc = create_autospec(EVC)
2351 1
        evc.archived = False
2352 1
        evc.is_enabled.return_value = True
2353
2354
        # Flow command is not 'add'
2355 1
        self.napp.circuits = {"00000000000011": evc}
2356 1
        self.napp.handle_flow_mod_error(event)
2357 1
        assert not evc.remove_current_flows.call_count
2358
2359
        # EVC is not enabled
2360 1
        event.content["error_command"] = "add"
2361 1
        evc.is_enabled.return_value = False
2362 1
        self.napp.handle_flow_mod_error(event)
2363 1
        assert not evc.remove_current_flows.call_count
2364
2365
        # EVC is archived
2366 1
        evc.is_enabled.return_value = True
2367 1
        evc.archived = True
2368 1
        self.napp.handle_flow_mod_error(event)
2369 1
        assert not evc.remove_current_flows.call_count
2370
2371
        # EVC does not exist in self.circuits
2372 1
        evc.archived = False
2373 1
        self.napp.circuits = {}
2374 1
        self.napp.handle_flow_mod_error(event)
2375 1
        assert not evc.remove_current_flows.call_count
2376
2377 1
    @patch("kytos.core.Controller.get_interface_by_id")
2378 1
    def test_uni_from_dict(self, _get_interface_by_id_mock):
2379
        """Test _uni_from_dict method."""
2380
        # pylint: disable=protected-access
2381
        # case1: early return on empty dict
2382 1
        assert not self.napp._uni_from_dict(None)
2383
2384
        # case2: invalid interface raises ValueError
2385 1
        _get_interface_by_id_mock.return_value = None
2386 1
        uni_dict = {
2387
            "interface_id": "00:01:1",
2388
            "tag": {"tag_type": 'vlan', "value": 81},
2389
        }
2390 1
        with pytest.raises(ValueError):
2391 1
            self.napp._uni_from_dict(uni_dict)
2392
2393
        # case3: success creation
2394 1
        uni_mock = get_uni_mocked(switch_id="00:01")
2395 1
        _get_interface_by_id_mock.return_value = uni_mock.interface
2396 1
        uni = self.napp._uni_from_dict(uni_dict)
2397 1
        assert uni == uni_mock
2398
2399
        # case4: success creation of tag list
2400 1
        uni_dict["tag"]["value"] = [[1, 10]]
2401 1
        uni = self.napp._uni_from_dict(uni_dict)
2402 1
        assert isinstance(uni.user_tag, TAGRange)
2403
2404
        # case5: success creation without tag
2405 1
        uni_mock.user_tag = None
2406 1
        del uni_dict["tag"]
2407 1
        uni = self.napp._uni_from_dict(uni_dict)
2408 1
        assert uni == uni_mock
2409
2410 1
    def test_handle_flow_delete(self):
2411
        """Test handle_flow_delete method"""
2412 1
        flow = MagicMock()
2413 1
        flow.cookie = 0xaa00000000000011
2414 1
        event = MagicMock()
2415 1
        event.content = {'flow': flow}
2416 1
        evc = create_autospec(EVC)
2417 1
        evc.set_flow_removed_at = MagicMock()
2418 1
        self.napp.circuits = {"00000000000011": evc}
2419 1
        self.napp.handle_flow_delete(event)
2420 1
        evc.set_flow_removed_at.assert_called_once()
2421
2422 1 View Code Duplication
    async def test_add_bulk_metadata(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2423
        """Test add_bulk_metadata method"""
2424 1
        self.napp.controller.loop = asyncio.get_running_loop()
2425 1
        evc_mock = create_autospec(EVC)
2426 1
        evc_mock.id = 1234
2427 1
        self.napp.circuits = {"1234": evc_mock}
2428 1
        payload = {
2429
            "circuit_ids": ["1234"],
2430
            "metadata1": 1,
2431
            "metadata2": 2
2432
        }
2433 1
        response = await self.api_client.post(
2434
            f"{self.base_endpoint}/v2/evc/metadata",
2435
            json=payload
2436
        )
2437 1
        assert response.status_code == 201
2438 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2439 1
        ids = payload.pop("circuit_ids")
2440 1
        assert args[0] == ids
2441 1
        assert args[1] == payload
2442 1
        assert args[2] == "add"
2443 1
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2444 1
        assert calls == 1
2445 1
        evc_mock.extend_metadata.assert_called_with(payload)
2446
2447 1
    async def test_add_bulk_metadata_empty_list(self):
2448
        """Test add_bulk_metadata method empty list"""
2449 1
        self.napp.controller.loop = asyncio.get_running_loop()
2450 1
        evc_mock = create_autospec(EVC)
2451 1
        evc_mock.id = 1234
2452 1
        self.napp.circuits = {"1234": evc_mock}
2453 1
        payload = {
2454
            "circuit_ids": [],
2455
            "metadata1": 1,
2456
            "metadata2": 2
2457
        }
2458 1
        response = await self.api_client.post(
2459
            f"{self.base_endpoint}/v2/evc/metadata",
2460
            json=payload
2461
        )
2462
        assert response.status_code == 400
2463
        assert "invalid" in response.json()["description"]
2464
2465 1
    async def test_add_bulk_metadata_no_id(self):
2466
        """Test add_bulk_metadata with unknown evc id"""
2467 1
        self.napp.controller.loop = asyncio.get_running_loop()
2468 1
        evc_mock = create_autospec(EVC)
2469 1
        evc_mock.id = 1234
2470 1
        self.napp.circuits = {"1234": evc_mock}
2471 1
        payload = {
2472
            "circuit_ids": ["1234", "4567"]
2473
        }
2474 1
        response = await self.api_client.post(
2475
            f"{self.base_endpoint}/v2/evc/metadata",
2476
            json=payload
2477
        )
2478
        assert response.status_code == 404
2479
2480 1
    async def test_add_bulk_metadata_no_circuits(self):
2481
        """Test add_bulk_metadata without circuit_ids"""
2482 1
        self.napp.controller.loop = asyncio.get_running_loop()
2483 1
        evc_mock = create_autospec(EVC)
2484 1
        evc_mock.id = 1234
2485 1
        self.napp.circuits = {"1234": evc_mock}
2486 1
        payload = {
2487
            "metadata": "data"
2488
        }
2489 1
        response = await self.api_client.post(
2490
            f"{self.base_endpoint}/v2/evc/metadata",
2491
            json=payload
2492
        )
2493
        assert response.status_code == 400
2494
2495 1 View Code Duplication
    async def test_delete_bulk_metadata(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2496
        """Test delete_metadata method"""
2497 1
        self.napp.controller.loop = asyncio.get_running_loop()
2498 1
        evc_mock = create_autospec(EVC)
2499 1
        evc_mock.id = 1234
2500 1
        self.napp.circuits = {"1234": evc_mock}
2501 1
        payload = {
2502
            "circuit_ids": ["1234"]
2503
        }
2504 1
        response = await self.api_client.request(
2505
            "DELETE",
2506
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2507
            json=payload
2508
        )
2509 1
        assert response.status_code == 200
2510 1
        args = self.napp.mongo_controller.update_evcs_metadata.call_args[0]
2511 1
        assert args[0] == payload["circuit_ids"]
2512 1
        assert args[1] == {"metadata1": ""}
2513 1
        assert args[2] == "del"
2514 1
        calls = self.napp.mongo_controller.update_evcs_metadata.call_count
2515 1
        assert calls == 1
2516 1
        assert evc_mock.remove_metadata.call_count == 1
2517
2518 1
    async def test_delete_bulk_metadata_error(self):
2519
        """Test bulk_delete_metadata with ciruit erroring"""
2520 1
        self.napp.controller.loop = asyncio.get_running_loop()
2521 1
        evc_mock = create_autospec(EVC)
2522 1
        evcs = [evc_mock, evc_mock]
2523 1
        self.napp.circuits = dict(zip(["1", "2"], evcs))
2524 1
        payload = {"circuit_ids": ["1", "2", "3"]}
2525 1
        response = await self.api_client.request(
2526
            "DELETE",
2527
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2528
            json=payload
2529
        )
2530
        assert response.status_code == 404, response.data
2531
        assert response.json()["description"] == ["3"]
2532
2533 1
    async def test_use_uni_tags(self):
2534
        """Test _use_uni_tags"""
2535 1
        self.napp.controller.loop = asyncio.get_running_loop()
2536 1
        evc_mock = create_autospec(EVC)
2537 1
        evc_mock.uni_a = "uni_a_mock"
2538 1
        evc_mock.uni_z = "uni_z_mock"
2539 1
        self.napp._use_uni_tags(evc_mock)
2540 1
        assert evc_mock._use_uni_vlan.call_count == 2
2541 1
        assert evc_mock._use_uni_vlan.call_args[0][0] == evc_mock.uni_z
2542
2543
        # One UNI tag is not available
2544 1
        evc_mock._use_uni_vlan.side_effect = [KytosTagError(""), None]
2545 1
        with pytest.raises(KytosTagError):
2546 1
            self.napp._use_uni_tags(evc_mock)
2547 1
        assert evc_mock._use_uni_vlan.call_count == 3
2548 1
        assert evc_mock.make_uni_vlan_available.call_count == 0
2549
2550 1
        evc_mock._use_uni_vlan.side_effect = [None, KytosTagError("")]
2551 1
        with pytest.raises(KytosTagError):
2552 1
            self.napp._use_uni_tags(evc_mock)
2553 1
        assert evc_mock._use_uni_vlan.call_count == 5
2554 1
        assert evc_mock.make_uni_vlan_available.call_count == 1
2555
2556 1
    def test_check_no_tag_duplication(self):
2557
        """Test _check_no_tag_duplication"""
2558 1
        evc = MagicMock()
2559 1
        evc.check_no_tag_duplicate = MagicMock()
2560 1
        evc.archived = False
2561 1
        evc.id = "1"
2562 1
        self.napp.circuits = {"1": evc}
2563 1
        evc_id = "2"
2564 1
        uni_a = get_uni_mocked(valid=True)
2565 1
        uni_z = get_uni_mocked(valid=True)
2566 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2567 1
        assert evc.check_no_tag_duplicate.call_count == 0
2568
2569 1
        uni_a.user_tag = None
2570 1
        uni_z.user_tag = None
2571 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, uni_z)
2572 1
        assert evc.check_no_tag_duplicate.call_count == 2
2573
2574 1
        self.napp._check_no_tag_duplication(evc_id, uni_a, None)
2575 1
        assert evc.check_no_tag_duplicate.call_count == 3
2576
2577 1
        self.napp._check_no_tag_duplication(evc_id, None, None)
2578 1
        assert evc.check_no_tag_duplicate.call_count == 3
2579
2580 1
    @patch("napps.kytos.mef_eline.main.time")
2581 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_up")
2582 1
    @patch("napps.kytos.mef_eline.main.Main.handle_interface_link_down")
2583 1
    def test_handle_on_interface_link_change(
2584
        self,
2585
        mock_down,
2586
        mock_up,
2587
        mock_time
2588
    ):
2589
        """Test handle_on_interface_link_change"""
2590 1
        mock_time.sleep.return_value = True
2591 1
        mock_intf = Mock()
2592 1
        mock_intf.id = "mock_intf"
2593
2594
        # Created/link_up
2595 1
        name = '.*.switch.interface.created'
2596 1
        content = {"interface": mock_intf}
2597 1
        event = KytosEvent(name=name, content=content)
2598 1
        self.napp.handle_on_interface_link_change(event)
2599 1
        assert mock_down.call_count == 0
2600 1
        assert mock_up.call_count == 1
2601
2602
        # Deleted/link_down
2603 1
        name = '.*.switch.interface.deleted'
2604 1
        event = KytosEvent(name=name, content=content)
2605 1
        self.napp.handle_on_interface_link_change(event)
2606 1
        assert mock_down.call_count == 1
2607 1
        assert mock_up.call_count == 1
2608
2609
        # Event delay
2610 1
        self.napp._intf_events[mock_intf.id]["last_acquired"] = "mock_time"
2611 1
        for _ in range(1, 6):
2612 1
            self.napp.handle_on_interface_link_change(event)
2613 1
        assert mock_down.call_count == 1
2614 1
        assert mock_up.call_count == 1
2615
2616 1
        self.napp._intf_events[mock_intf.id].pop("last_acquired")
2617 1
        self.napp.handle_on_interface_link_change(event)
2618 1
        assert mock_down.call_count == 2
2619 1
        assert mock_up.call_count == 1
2620
2621
        # Out of order event
2622 1
        event = KytosEvent(name=name, content=content)
2623 1
        self.napp._intf_events[mock_intf.id]["event"] = Mock(timestamp=now())
2624
2625 1
        self.napp.handle_on_interface_link_change(event)
2626 1
        assert mock_down.call_count == 2
2627
        assert mock_up.call_count == 1
2628