Test Failed
Pull Request — master (#480)
by Aldo
04:19
created

build.tests.unit.test_main   F

Complexity

Total Complexity 91

Size/Duplication

Total Lines 2513
Duplicated Lines 8.52 %

Test Coverage

Coverage 91.34%

Importance

Changes 0
Metric Value
eloc 1876
dl 214
loc 2513
rs 0.8
c 0
b 0
f 0
ccs 1118
cts 1224
cp 0.9134
wmc 91

78 Methods

Rating   Name   Duplication   Size   Complexity  
A TestMain.setup_method() 0 18 2
A TestMain.test_get_event_listeners() 0 12 2
A TestMain.test_execute() 0 19 1
B TestMain._add_mongodb_schedule_data() 0 52 1
A TestMain.test_execute_consistency() 0 42 1
A TestMain.test_add_metadata_no_body() 0 9 1
A TestMain.test_add_metadata_no_evc() 0 11 1
A TestMain.test_delete_metadata_no_evc() 0 8 1
B TestMain.test_handle_evc_affected_by_link_down() 0 59 1
A TestMain.test_get_metadata() 0 12 1
B TestMain.test_update_circuit_invalid_json() 72 72 1
A TestMain.test_list_no_circuits_stored() 0 9 1
B TestMain.test_create_schedule() 0 57 1
A TestMain.test_circuit_with_invalid_id() 0 7 1
A TestMain._uni_from_dict_side_effect() 0 5 1
A TestMain.test_create_circuit_case_8() 0 29 1
A TestMain.test_uni_from_dict() 0 32 2
A TestMain.test_create_a_circuit_case_5() 0 32 1
B TestMain.test_handle_link_down() 0 152 1
B TestMain.test_update_schedule() 0 64 1
A TestMain.test_circuit_with_valid_id() 0 9 1
A TestMain.test_execute_consistency_wait_for() 0 33 1
A TestMain.test_check_no_tag_duplication() 0 23 1
A TestMain.test_update_no_schedule() 0 13 1
A TestMain.test_add_metadata_malformed_json() 0 12 1
A TestMain.test_get_specific_schedules_from_mongodb_not_found() 0 13 1
A TestMain.test_create_a_circuit_case_4() 0 37 1
B TestMain.test_delete_archived_evc() 0 82 1
B TestMain.test_update_disabled_intra_switch() 0 71 1
B TestMain.test_delete_schedule() 0 55 1
B TestMain.test_update_circuit() 0 134 1
A TestMain.test_list_schedules_from_mongodb() 0 52 1
A TestMain.test_evc_from_dict_paths() 0 49 1
A TestMain.test_add_bulk_metadata_no_circuits() 0 14 1
A TestMain.test_delete_metadata() 0 11 1
B TestMain.test_create_circuit_already_enabled() 0 69 1
A TestMain.test_uni_from_dict_non_existent_intf() 0 8 2
B TestMain.test_create_a_circuit_case_1() 0 99 1
A TestMain.test_create_a_circuit_case_3() 0 13 1
A TestMain.test_link_from_dict_non_existent_intf() 0 9 2
A TestMain.test_delete_bulk_metadata_error() 0 14 1
A TestMain.test_list_with_archived_circuits_all() 0 14 1
A TestMain.test_handle_on_interface_link_change() 0 48 2
A TestMain.test_list_without_circuits() 0 8 1
A TestMain.test_add_bulk_metadata_no_id() 0 14 1
A TestMain.test_list_schedules__no_data_stored() 0 9 1
B TestMain.test_update_circuit_invalid_path() 0 84 1
A TestMain.test_create_circuit_case_5() 0 38 1
A TestMain.test_create_circuit_case_6() 0 17 1
A TestMain.test_handle_link_up() 0 15 1
A TestMain.test_redeploy_evc_deleted() 0 8 1
A TestMain.test_add_bulk_metadata() 24 24 1
A TestMain.test_create_a_circuit_invalid_queue_id() 0 23 1
A TestMain.test_get_specific_schedule_from_mongodb() 0 23 1
A TestMain.test_add_metadata() 0 16 1
A TestMain.test_delete_schedule_not_found() 0 7 1
A TestMain.test_delete_no_evc() 0 8 1
A TestMain.test_list_with_circuits_stored() 14 14 1
A TestMain.test_add_bulk_metadata_empty_list() 0 17 1
A TestMain.test_add_metadata_wrong_content_type() 0 11 1
A TestMain.test_evc_from_dict() 0 33 1
A TestMain.test_list_with_archived_circuits_archived() 17 17 1
B TestMain.test_get_evcs_by_svc_level() 0 27 5
A TestMain.test_redeploy_evc_disabled() 0 10 1
A TestMain.test_evc_from_dict_links() 0 53 1
B TestMain.test_update_evc_no_json_mime() 65 65 1
A TestMain.test_create_a_circuit_case_2() 0 9 1
A TestMain.test_cleanup_evcs_old_path() 0 27 1
A TestMain.test_get_circuit_not_found() 0 6 1
A TestMain.test_delete_bulk_metadata() 22 22 1
A TestMain.test_load_all_evcs() 0 21 1
A TestMain.test_use_uni_tags() 0 22 3
A TestMain.test_redeploy_evc() 0 10 1
A TestMain.test_handle_flow_mod_error() 0 12 1
A TestMain.test_create_schedule_invalid_request() 0 47 1
A TestMain.test_load_evc() 0 29 1
A TestMain.test_create_circuit_case_7() 0 38 1
A TestMain.test_handle_flow_delete() 0 11 1

1 Function

Rating   Name   Duplication   Size   Complexity  
A test_on_table_enabled() 0 31 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like build.tests.unit.test_main often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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