Passed
Push — master ( 5cb22e...3e1f49 )
by Vinicius
12:54 queued 10:13
created

build.tests.unit.test_main.TestMain.test_handle_topology_update()   A

Complexity

Conditions 1

Size

Total Lines 16
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 1

Importance

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