Passed
Pull Request — master (#330)
by
unknown
07:02
created

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

Complexity

Conditions 1

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 14
nop 3
dl 0
loc 19
ccs 14
cts 14
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": 1, "value": 80},
192
            },
193
            "uni_z": {
194
                "interface_id": "00:00:00:00:00:00:00:02:2",
195
                "tag": {"tag_type": 1, "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": 1, "value": 80},
231
            },
232
            "uni_z": {
233
                "interface_id": "00:00:00:00:00:00:00:02:2",
234
                "tag": {"tag_type": 1, "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": 1, "value": 80},
280
            },
281
            "uni_z": {
282
                "interface_id": "00:00:00:00:00:00:00:02:2",
283
                "tag": {"tag_type": 1, "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": 1,
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.models.evc.EVC.deploy")
401 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
402 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
403 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
404 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
405 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
406 1
    async def test_create_a_circuit_case_1(
407
        self,
408
        validate_mock,
409
        evc_as_dict_mock,
410
        mongo_controller_upsert_mock,
411
        uni_from_dict_mock,
412
        sched_add_mock,
413
        evc_deploy_mock,
414
        event_loop
415
    ):
416
        """Test create a new circuit."""
417
        # pylint: disable=too-many-locals
418 1
        self.napp.controller.loop = event_loop
419 1
        validate_mock.return_value = True
420 1
        mongo_controller_upsert_mock.return_value = True
421 1
        evc_deploy_mock.return_value = True
422 1
        uni1 = create_autospec(UNI)
423 1
        uni2 = create_autospec(UNI)
424 1
        uni1.interface = create_autospec(Interface)
425 1
        uni2.interface = create_autospec(Interface)
426 1
        uni1.interface.switch = MagicMock()
427 1
        uni1.interface.switch.return_value = "00:00:00:00:00:00:00:01"
428 1
        uni1.interface.switch.status = EntityStatus.UP
429 1
        uni2.interface.switch = MagicMock()
430 1
        uni2.interface.switch.return_value = "00:00:00:00:00:00:00:02"
431 1
        uni2.interface.switch.status = EntityStatus.UP
432 1
        uni_from_dict_mock.side_effect = [uni1, uni2]
433 1
        evc_as_dict_mock.return_value = {}
434 1
        sched_add_mock.return_value = True
435 1
        self.napp.mongo_controller.get_circuits.return_value = {}
436
437 1
        url = f"{self.base_endpoint}/v2/evc/"
438 1
        payload = {
439
            "name": "my evc1",
440
            "frequency": "* * * * *",
441
            "uni_a": {
442
                "interface_id": "00:00:00:00:00:00:00:01:1",
443
                "tag": {"tag_type": 1, "value": 80},
444
            },
445
            "uni_z": {
446
                "interface_id": "00:00:00:00:00:00:00:02:2",
447
                "tag": {"tag_type": 1, "value": 1},
448
            },
449
            "dynamic_backup_path": True,
450
            "primary_constraints": {
451
                "spf_max_path_cost": 8,
452
                "mandatory_metrics": {
453
                    "ownership": "red"
454
                }
455
            },
456
            "secondary_constraints": {
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": 1, "value": 80},
541
            },
542
            "uni_z": {
543
                "interface_id": "00:00:00:00:00:00:00:02:2",
544
                "tag": {"tag_type": 1, "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
    async def test_create_a_circuit_invalid_queue_id(self, event_loop):
559
        """Test create a new circuit with invalid queue_id."""
560 1
        self.napp.controller.loop = event_loop
561 1
        url = f"{self.base_endpoint}/v2/evc/"
562
563 1
        payload = {
564
            "name": "my evc1",
565
            "queue_id": 8,
566
            "uni_a": {
567
                "interface_id": "00:00:00:00:00:00:00:01:76",
568
                "tag": {"tag_type": 1, "value": 80},
569
            },
570
            "uni_z": {
571
                "interface_id": "00:00:00:00:00:00:00:02:2",
572
                "tag": {"tag_type": 1, "value": 1},
573
            },
574
        }
575 1
        response = await self.api_client.post(url, json=payload)
576 1
        current_data = response.json()
577 1
        expected_data = "8 is greater than the maximum of 7"
578
579 1
        assert response.status_code == 400
580 1
        assert expected_data in current_data["description"]
581
582 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
583 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
584 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
585 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
586 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
587 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
588 1
    async def test_create_circuit_already_enabled(
589
        self,
590
        evc_as_dict_mock,
591
        validate_mock,
592
        mongo_controller_upsert_mock,
593
        uni_from_dict_mock,
594
        sched_add_mock,
595
        evc_deploy_mock,
596
        event_loop
597
    ):
598
        """Test create an already created circuit."""
599
        # pylint: disable=too-many-locals
600 1
        self.napp.controller.loop = event_loop
601 1
        validate_mock.return_value = True
602 1
        mongo_controller_upsert_mock.return_value = True
603 1
        sched_add_mock.return_value = True
604 1
        evc_deploy_mock.return_value = True
605 1
        uni1 = create_autospec(UNI)
606 1
        uni2 = create_autospec(UNI)
607 1
        uni1.interface = create_autospec(Interface)
608 1
        uni2.interface = create_autospec(Interface)
609 1
        uni1.interface.switch = MagicMock()
610 1
        uni1.interface.switch.return_value = "00:00:00:00:00:00:00:01"
611 1
        uni1.interface.switch.status = EntityStatus.UP
612 1
        uni2.interface.switch = MagicMock()
613 1
        uni2.interface.switch.return_value = "00:00:00:00:00:00:00:02"
614 1
        uni2.interface.switch.status = EntityStatus.UP
615 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
616
617 1
        payload = {
618
            "name": "my evc1",
619
            "uni_a": {
620
                "interface_id": "00:00:00:00:00:00:00:01:1",
621
                "tag": {"tag_type": 1, "value": 80},
622
            },
623
            "uni_z": {
624
                "interface_id": "00:00:00:00:00:00:00:02:2",
625
                "tag": {"tag_type": 1, "value": 1},
626
            },
627
            "dynamic_backup_path": True,
628
        }
629
630 1
        evc_as_dict_mock.return_value = payload
631 1
        response = await self.api_client.post(
632
            f"{self.base_endpoint}/v2/evc/",
633
            json=payload
634
        )
635 1
        assert 201 == response.status_code
636
637 1
        response = await self.api_client.post(
638
            f"{self.base_endpoint}/v2/evc/",
639
            json=payload
640
        )
641 1
        current_data = response.json()
642 1
        expected_data = "The EVC already exists."
643 1
        assert current_data["description"] == expected_data
644 1
        assert 409 == response.status_code
645
646 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
647 1
    async def test_create_circuit_case_5(self, uni_from_dict_mock, event_loop):
648
        """Test when neither primary path nor dynamic_backup_path is set."""
649 1
        self.napp.controller.loop = event_loop
650 1
        url = f"{self.base_endpoint}/v2/evc/"
651 1
        uni1 = create_autospec(UNI)
652 1
        uni2 = create_autospec(UNI)
653 1
        uni1.interface = create_autospec(Interface)
654 1
        uni2.interface = create_autospec(Interface)
655 1
        uni1.interface.switch = MagicMock()
656 1
        uni1.interface.switch.return_value = "00:00:00:00:00:00:00:01"
657 1
        uni1.interface.switch.status = EntityStatus.UP
658 1
        uni2.interface.switch = MagicMock()
659 1
        uni2.interface.switch.return_value = "00:00:00:00:00:00:00:02"
660 1
        uni2.interface.switch.status = EntityStatus.UP
661 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
662
663 1
        payload = {
664
            "name": "my evc1",
665
            "frequency": "* * * * *",
666
            "uni_a": {
667
                "interface_id": "00:00:00:00:00:00:00:01:1",
668
                "tag": {"tag_type": 1, "value": 80},
669
            },
670
            "uni_z": {
671
                "interface_id": "00:00:00:00:00:00:00:02:2",
672
                "tag": {"tag_type": 1, "value": 1},
673
            },
674
        }
675
676 1
        response = await self.api_client.post(url, json=payload)
677 1
        current_data = response.json()
678 1
        expected_data = "The EVC must have a primary path "
679 1
        expected_data += "or allow dynamic paths."
680 1
        assert 400 == response.status_code, response.data
681 1
        assert current_data["description"] == expected_data
682
683 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
684 1
    async def test_create_circuit_case_6(
685
        self,
686
        uni_from_dict_mock,
687
        event_loop
688
    ):
689
        """Test create a circuit with a disabled switch."""
690
        # pylint: disable=too-many-locals
691 1
        self.napp.controller.loop = event_loop
692 1
        uni1 = create_autospec(UNI)
693 1
        uni2 = create_autospec(UNI)
694 1
        uni1.interface = create_autospec(Interface)
695 1
        uni2.interface = create_autospec(Interface)
696 1
        uni1.interface.switch = MagicMock()
697 1
        uni1.interface.switch.return_value = "00:00:00:00:00:00:00:01"
698 1
        uni1.interface.switch.status = EntityStatus.UP
699 1
        uni2.interface.switch = MagicMock()
700 1
        uni2.interface.switch.return_value = "00:00:00:00:00:00:00:02"
701 1
        uni2.interface.switch.status = EntityStatus.DISABLED
702 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
703
704 1
        payload = {
705
            "name": "my evc1",
706
            "uni_a": {
707
                "interface_id": "00:00:00:00:00:00:00:01:1",
708
                "tag": {"tag_type": 1, "value": 80},
709
            },
710
            "uni_z": {
711
                "interface_id": "00:00:00:00:00:00:00:02:2",
712
                "tag": {"tag_type": 1, "value": 1},
713
            },
714
            "dynamic_backup_path": True,
715
        }
716
717 1
        response = await self.api_client.post(
718
            f"{self.base_endpoint}/v2/evc/",
719
            json=payload
720
        )
721 1
        assert 409 == response.status_code
722
723 1
    @patch("napps.kytos.mef_eline.main.Main._link_from_dict")
724 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
725 1
    async def test_create_circuit_case_7(
726
        self,
727
        uni_from_dict_mock,
728
        link_from_dict_mock,
729
        event_loop
730
    ):
731
        """Test create a circuit with a disabled switch in static path."""
732
        # pylint: disable=too-many-locals
733 1
        self.napp.controller.loop = event_loop
734 1
        link_from_dict_mock.return_value = 1
735 1
        uni1 = create_autospec(UNI)
736 1
        uni2 = create_autospec(UNI)
737 1
        uni1.interface = create_autospec(Interface)
738 1
        uni2.interface = create_autospec(Interface)
739 1
        uni1.interface.switch = MagicMock()
740 1
        uni1.interface.switch.return_value = "00:00:00:00:00:00:00:01"
741 1
        uni1.interface.switch.status = EntityStatus.UP
742 1
        uni2.interface.switch = MagicMock()
743 1
        uni2.interface.switch.return_value = "00:00:00:00:00:00:00:02"
744 1
        uni2.interface.switch.status = EntityStatus.DISABLED
745 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
746
747 1
        payload = {
748
            "name": "my evc1",
749
            "uni_a": {
750
                "interface_id": "00:00:00:00:00:00:00:01:1",
751
                "tag": {"tag_type": 1, "value": 80},
752
            },
753
            "uni_z": {
754
                "interface_id": "00:00:00:00:00:00:00:03:2",
755
                "tag": {"tag_type": 1, "value": 1},
756
            },
757
            "primary_path": [
758
                {"endpoint_a": {"id": "00:00:00:00:00:00:00:01:3"},
759
                 "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"}},
760
                {"endpoint_a": {"id": "00:00:00:00:00:00:00:02:3"},
761
                 "endpoint_b": {"id": "00:00:00:00:00:00:00:03:2"}}
762
            ],
763
        }
764
765 1
        response = await self.api_client.post(
766
            f"{self.base_endpoint}/v2/evc/",
767
            json=payload
768
        )
769 1
        assert 409 == response.status_code
770
771 1
    async def test_redeploy_evc(self):
772
        """Test endpoint to redeploy an EVC."""
773 1
        evc1 = MagicMock()
774 1
        evc1.is_enabled.return_value = True
775 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
776 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
777 1
        response = await self.api_client.patch(url)
778 1
        assert response.status_code == 202, response.data
779
780 1
    async def test_redeploy_evc_disabled(self):
781
        """Test endpoint to redeploy an EVC."""
782 1
        evc1 = MagicMock()
783 1
        evc1.is_enabled.return_value = False
784 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
785 1
        url = f"{self.base_endpoint}/v2/evc/1/redeploy"
786 1
        response = await self.api_client.patch(url)
787 1
        assert response.status_code == 409, response.data
788
789 1
    async def test_redeploy_evc_deleted(self):
790
        """Test endpoint to redeploy an EVC."""
791 1
        evc1 = MagicMock()
792 1
        evc1.is_enabled.return_value = True
793 1
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
794 1
        url = f"{self.base_endpoint}/v2/evc/3/redeploy"
795 1
        response = await self.api_client.patch(url)
796 1
        assert response.status_code == 404, response.data
797
798 1
    async def test_list_schedules__no_data_stored(self):
799
        """Test if list circuits return all circuits stored."""
800 1
        self.napp.mongo_controller.get_circuits.return_value = {"circuits": {}}
801
802 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
803
804 1
        response = await self.api_client.get(url)
805 1
        assert response.status_code == 200
806 1
        assert not response.json()
807
808 1
    def _add_mongodb_schedule_data(self, data_mock):
809
        """Add schedule data to mongodb mock object."""
810 1
        circuits = {"circuits": {}}
811 1
        payload_1 = {
812
            "id": "aa:aa:aa",
813
            "name": "my evc1",
814
            "uni_a": {
815
                "interface_id": "00:00:00:00:00:00:00:01:1",
816
                "tag": {"tag_type": 1, "value": 80},
817
            },
818
            "uni_z": {
819
                "interface_id": "00:00:00:00:00:00:00:02:2",
820
                "tag": {"tag_type": 1, "value": 1},
821
            },
822
            "circuit_scheduler": [
823
                {"id": "1", "frequency": "* * * * *", "action": "create"},
824
                {"id": "2", "frequency": "1 * * * *", "action": "remove"},
825
            ],
826
        }
827 1
        circuits["circuits"].update({"aa:aa:aa": payload_1})
828 1
        payload_2 = {
829
            "id": "bb:bb:bb",
830
            "name": "my second evc2",
831
            "uni_a": {
832
                "interface_id": "00:00:00:00:00:00:00:01:2",
833
                "tag": {"tag_type": 1, "value": 90},
834
            },
835
            "uni_z": {
836
                "interface_id": "00:00:00:00:00:00:00:03:2",
837
                "tag": {"tag_type": 1, "value": 100},
838
            },
839
            "circuit_scheduler": [
840
                {"id": "3", "frequency": "1 * * * *", "action": "create"},
841
                {"id": "4", "frequency": "2 * * * *", "action": "remove"},
842
            ],
843
        }
844 1
        circuits["circuits"].update({"bb:bb:bb": payload_2})
845 1
        payload_3 = {
846
            "id": "cc:cc:cc",
847
            "name": "my third evc3",
848
            "uni_a": {
849
                "interface_id": "00:00:00:00:00:00:00:03:1",
850
                "tag": {"tag_type": 1, "value": 90},
851
            },
852
            "uni_z": {
853
                "interface_id": "00:00:00:00:00:00:00:04:2",
854
                "tag": {"tag_type": 1, "value": 100},
855
            },
856
        }
857 1
        circuits["circuits"].update({"cc:cc:cc": payload_3})
858
        # Add one circuit to the mongodb.
859 1
        data_mock.return_value = circuits
860
861 1
    async def test_list_schedules_from_mongodb(self):
862
        """Test if list circuits return specific circuits stored."""
863 1
        self._add_mongodb_schedule_data(
864
            self.napp.mongo_controller.get_circuits
865
        )
866
867 1
        url = f"{self.base_endpoint}/v2/evc/schedule"
868
869
        # Call URL
870 1
        response = await self.api_client.get(url)
871
        # Expected JSON data from response
872 1
        expected = [
873
            {
874
                "circuit_id": "aa:aa:aa",
875
                "schedule": {
876
                    "action": "create",
877
                    "frequency": "* * * * *",
878
                    "id": "1",
879
                },
880
                "schedule_id": "1",
881
            },
882
            {
883
                "circuit_id": "aa:aa:aa",
884
                "schedule": {
885
                    "action": "remove",
886
                    "frequency": "1 * * * *",
887
                    "id": "2",
888
                },
889
                "schedule_id": "2",
890
            },
891
            {
892
                "circuit_id": "bb:bb:bb",
893
                "schedule": {
894
                    "action": "create",
895
                    "frequency": "1 * * * *",
896
                    "id": "3",
897
                },
898
                "schedule_id": "3",
899
            },
900
            {
901
                "circuit_id": "bb:bb:bb",
902
                "schedule": {
903
                    "action": "remove",
904
                    "frequency": "2 * * * *",
905
                    "id": "4",
906
                },
907
                "schedule_id": "4",
908
            },
909
        ]
910
911 1
        assert response.status_code == 200
912 1
        assert expected == response.json()
913
914 1
    async def test_get_specific_schedule_from_mongodb(self):
915
        """Test get schedules from a circuit."""
916 1
        self._add_mongodb_schedule_data(
917
            self.napp.mongo_controller.get_circuits
918
        )
919
920 1
        requested_circuit_id = "bb:bb:bb"
921 1
        evc = self.napp.mongo_controller.get_circuits()
922 1
        evc = evc["circuits"][requested_circuit_id]
923 1
        self.napp.mongo_controller.get_circuit.return_value = evc
924 1
        url = f"{self.base_endpoint}/v2/evc/{requested_circuit_id}"
925
926
        # Call URL
927 1
        response = await self.api_client.get(url)
928
929
        # Expected JSON data from response
930 1
        expected = [
931
            {"action": "create", "frequency": "1 * * * *", "id": "3"},
932
            {"action": "remove", "frequency": "2 * * * *", "id": "4"},
933
        ]
934
935 1
        assert response.status_code == 200
936 1
        assert expected == response.json()["circuit_scheduler"]
937
938 1
    async def test_get_specific_schedules_from_mongodb_not_found(self):
939
        """Test get specific schedule ID that does not exist."""
940 1
        requested_id = "blah"
941 1
        self.napp.mongo_controller.get_circuit.return_value = None
942 1
        url = f"{self.base_endpoint}/v2/evc/{requested_id}"
943
944
        # Call URL
945 1
        response = await self.api_client.get(url)
946
947 1
        expected = "circuit_id blah not found"
948
        # Assert response not found
949 1
        assert response.status_code == 404
950 1
        assert expected == response.json()["description"]
951
952 1
    def _uni_from_dict_side_effect(self, uni_dict):
953 1
        interface_id = uni_dict.get("interface_id")
954 1
        tag_dict = uni_dict.get("tag")
955 1
        interface = Interface(interface_id, "0", MagicMock(id="1"))
956 1
        return UNI(interface, tag_dict)
957
958 1
    @patch("apscheduler.schedulers.background.BackgroundScheduler.add_job")
959 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
960 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
961 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
962 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
963 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
964 1
    async def test_create_schedule(
965
        self,
966
        validate_mock,
967
        evc_as_dict_mock,
968
        mongo_controller_upsert_mock,
969
        uni_from_dict_mock,
970
        sched_add_mock,
971
        scheduler_add_job_mock,
972
        event_loop
973
    ):
974
        """Test create a circuit schedule."""
975 1
        self.napp.controller.loop = event_loop
976 1
        validate_mock.return_value = True
977 1
        mongo_controller_upsert_mock.return_value = True
978 1
        uni_from_dict_mock.side_effect = self._uni_from_dict_side_effect
979 1
        evc_as_dict_mock.return_value = {}
980 1
        sched_add_mock.return_value = True
981
982 1
        self._add_mongodb_schedule_data(
983
            self.napp.mongo_controller.get_circuits
984
        )
985
986 1
        requested_id = "bb:bb:bb"
987 1
        url = f"{self.base_endpoint}/v2/evc/schedule/"
988
989 1
        payload = {
990
            "circuit_id": requested_id,
991
            "schedule": {"frequency": "1 * * * *", "action": "create"},
992
            "metadata": {"metadata1": "test_data"},
993
        }
994
995
        # Call URL
996 1
        response = await self.api_client.post(url, json=payload)
997 1
        response_json = response.json()
998
999 1
        assert response.status_code == 201
1000 1
        scheduler_add_job_mock.assert_called_once()
1001 1
        mongo_controller_upsert_mock.assert_called_once()
1002 1
        assert payload["schedule"]["frequency"] == response_json["frequency"]
1003 1
        assert payload["schedule"]["action"] == response_json["action"]
1004 1
        assert response_json["id"] is not None
1005
1006
        # Case 2: there is no schedule
1007 1
        payload = {
1008
              "circuit_id": "cc:cc:cc",
1009
              "schedule": {
1010
                "frequency": "1 * * * *",
1011
                "action": "create"
1012
              }
1013
            }
1014 1
        response = await self.api_client.post(url, json=payload)
1015 1
        assert response.status_code == 201
1016
1017 1
    async def test_create_schedule_invalid_request(self, event_loop):
1018
        """Test create schedule API with invalid request."""
1019 1
        self.napp.controller.loop = event_loop
1020 1
        evc1 = MagicMock()
1021 1
        self.napp.circuits = {'bb:bb:bb': evc1}
1022 1
        url = f'{self.base_endpoint}/v2/evc/schedule/'
1023
1024
        # case 1: empty post
1025 1
        response = await self.api_client.post(url, json={})
1026 1
        assert response.status_code == 400
1027
1028
        # case 2: content-type not specified
1029 1
        payload = {
1030
            "circuit_id": "bb:bb:bb",
1031
            "schedule": {
1032
                "frequency": "1 * * * *",
1033
                "action": "create"
1034
            }
1035
        }
1036 1
        response = await self.api_client.post(url, json=payload)
1037 1
        assert response.status_code == 409
1038
1039
        # case 3: not a dictionary
1040 1
        payload = []
1041 1
        response = await self.api_client.post(url, json=payload)
1042 1
        assert response.status_code == 400
1043
1044
        # case 4: missing circuit id
1045 1
        payload = {
1046
            "schedule": {
1047
                "frequency": "1 * * * *",
1048
                "action": "create"
1049
            }
1050
        }
1051 1
        response = await self.api_client.post(url, json=payload)
1052 1
        assert response.status_code == 400
1053
1054
        # case 5: missing schedule
1055 1
        payload = {
1056
            "circuit_id": "bb:bb:bb"
1057
        }
1058 1
        response = await self.api_client.post(url, json=payload)
1059 1
        assert response.status_code == 400
1060
1061
        # case 6: invalid circuit
1062 1
        payload = {
1063
            "circuit_id": "xx:xx:xx",
1064
            "schedule": {
1065
                "frequency": "1 * * * *",
1066
                "action": "create"
1067
            }
1068
        }
1069 1
        response = await self.api_client.post(url, json=payload)
1070 1
        assert response.status_code == 404
1071
1072
        # case 7: archived or deleted evc
1073 1
        evc1.archived.return_value = True
1074 1
        payload = {
1075
            "circuit_id": "bb:bb:bb",
1076
            "schedule": {
1077
                "frequency": "1 * * * *",
1078
                "action": "create"
1079
            }
1080
        }
1081 1
        response = await self.api_client.post(url, json=payload)
1082 1
        assert response.status_code == 409
1083
1084
        # case 8: invalid json
1085 1
        response = await self.api_client.post(url, json="test")
1086 1
        assert response.status_code == 400
1087
1088 1
    @patch('apscheduler.schedulers.background.BackgroundScheduler.remove_job')
1089 1
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1090 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1091 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1092 1
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1093 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1094 1
    async def test_update_schedule(
1095
        self,
1096
        validate_mock,
1097
        evc_as_dict_mock,
1098
        mongo_controller_upsert_mock,
1099
        uni_from_dict_mock,
1100
        sched_add_mock,
1101
        scheduler_remove_job_mock,
1102
        event_loop
1103
    ):
1104
        """Test create a circuit schedule."""
1105 1
        self.napp.controller.loop = event_loop
1106 1
        mongo_payload_1 = {
1107
            "circuits": {
1108
                "aa:aa:aa": {
1109
                    "id": "aa:aa:aa",
1110
                    "name": "my evc1",
1111
                    "uni_a": {
1112
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1113
                        "tag": {"tag_type": 1, "value": 80},
1114
                    },
1115
                    "uni_z": {
1116
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1117
                        "tag": {"tag_type": 1, "value": 1},
1118
                    },
1119
                    "circuit_scheduler": [
1120
                        {
1121
                            "id": "1",
1122
                            "frequency": "* * * * *",
1123
                            "action": "create"
1124
                        }
1125
                    ],
1126
                }
1127
            }
1128
        }
1129
1130 1
        validate_mock.return_value = True
1131 1
        mongo_controller_upsert_mock.return_value = True
1132 1
        sched_add_mock.return_value = True
1133 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1134 1
        evc_as_dict_mock.return_value = {}
1135 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1136 1
        scheduler_remove_job_mock.return_value = True
1137
1138 1
        requested_schedule_id = "1"
1139 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1140
1141 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1142
1143
        # Call URL
1144 1
        response = await self.api_client.patch(url, json=payload)
1145 1
        response_json = response.json()
1146
1147 1
        assert response.status_code == 200
1148 1
        scheduler_remove_job_mock.assert_called_once()
1149 1
        mongo_controller_upsert_mock.assert_called_once()
1150 1
        assert payload["frequency"] == response_json["frequency"]
1151 1
        assert payload["action"] == response_json["action"]
1152 1
        assert response_json["id"] is not None
1153
1154 1
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1155 1
    async def test_update_no_schedule(
1156
        self, find_evc_by_schedule_id_mock, event_loop
1157
    ):
1158
        """Test update a circuit schedule."""
1159 1
        self.napp.controller.loop = event_loop
1160 1
        url = f"{self.base_endpoint}/v2/evc/schedule/1"
1161 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1162
1163 1
        find_evc_by_schedule_id_mock.return_value = None, None
1164
1165 1
        response = await self.api_client.patch(url, json=payload)
1166 1
        assert response.status_code == 404
1167
1168 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1169 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1170 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1171 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1172 1
    async def test_update_schedule_archived(
1173
        self,
1174
        validate_mock,
1175
        evc_as_dict_mock,
1176
        uni_from_dict_mock,
1177
        sched_add_mock,
1178
        event_loop
1179
    ):
1180
        """Test create a circuit schedule."""
1181 1
        self.napp.controller.loop = event_loop
1182 1
        mongo_payload_1 = {
1183
            "circuits": {
1184
                "aa:aa:aa": {
1185
                    "id": "aa:aa:aa",
1186
                    "name": "my evc1",
1187
                    "archived": True,
1188
                    "circuit_scheduler": [
1189
                        {
1190
                            "id": "1",
1191
                            "frequency": "* * * * *",
1192
                            "action": "create"
1193
                        }
1194
                    ],
1195
                }
1196
            }
1197
        }
1198
1199 1
        validate_mock.return_value = True
1200 1
        sched_add_mock.return_value = True
1201 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1202 1
        evc_as_dict_mock.return_value = {}
1203 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1204
1205 1
        requested_schedule_id = "1"
1206 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1207
1208 1
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1209
1210
        # Call URL
1211 1
        response = await self.api_client.patch(url, json=payload)
1212 1
        assert response.status_code == 409
1213
1214 1
    @patch("apscheduler.schedulers.background.BackgroundScheduler.remove_job")
1215 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1216 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1217 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1218 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1219 1
    async def test_delete_schedule(self, *args):
1220
        """Test create a circuit schedule."""
1221 1
        (
1222
            validate_mock,
1223
            evc_as_dict_mock,
1224
            mongo_controller_upsert_mock,
1225
            uni_from_dict_mock,
1226
            scheduler_remove_job_mock,
1227
        ) = args
1228
1229 1
        mongo_payload_1 = {
1230
            "circuits": {
1231
                "2": {
1232
                    "id": "2",
1233
                    "name": "my evc1",
1234
                    "uni_a": {
1235
                        "interface_id": "00:00:00:00:00:00:00:01:1",
1236
                        "tag": {"tag_type": 1, "value": 80},
1237
                    },
1238
                    "uni_z": {
1239
                        "interface_id": "00:00:00:00:00:00:00:02:2",
1240
                        "tag": {"tag_type": 1, "value": 1},
1241
                    },
1242
                    "circuit_scheduler": [
1243
                        {
1244
                            "id": "1",
1245
                            "frequency": "* * * * *",
1246
                            "action": "create"
1247
                        }
1248
                    ],
1249
                }
1250
            }
1251
        }
1252 1
        validate_mock.return_value = True
1253 1
        mongo_controller_upsert_mock.return_value = True
1254 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1255 1
        evc_as_dict_mock.return_value = {}
1256 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1257 1
        scheduler_remove_job_mock.return_value = True
1258
1259 1
        requested_schedule_id = "1"
1260 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1261
1262
        # Call URL
1263 1
        response = await self.api_client.delete(url)
1264
1265 1
        assert response.status_code == 200
1266 1
        scheduler_remove_job_mock.assert_called_once()
1267 1
        mongo_controller_upsert_mock.assert_called_once()
1268 1
        assert "Schedule removed" in f"{response.json()}"
1269
1270 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1271 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1272 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1273 1
    async def test_delete_schedule_archived(self, *args):
1274
        """Test create a circuit schedule."""
1275 1
        (
1276
            validate_mock,
1277
            evc_as_dict_mock,
1278
            uni_from_dict_mock,
1279
        ) = args
1280
1281 1
        mongo_payload_1 = {
1282
            "circuits": {
1283
                "2": {
1284
                    "id": "2",
1285
                    "name": "my evc1",
1286
                    "archived": True,
1287
                    "circuit_scheduler": [
1288
                        {
1289
                            "id": "1",
1290
                            "frequency": "* * * * *",
1291
                            "action": "create"
1292
                        }
1293
                    ],
1294
                }
1295
            }
1296
        }
1297
1298 1
        validate_mock.return_value = True
1299 1
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1300 1
        evc_as_dict_mock.return_value = {}
1301 1
        self.napp.mongo_controller.get_circuits.return_value = mongo_payload_1
1302
1303 1
        requested_schedule_id = "1"
1304 1
        url = f"{self.base_endpoint}/v2/evc/schedule/{requested_schedule_id}"
1305
1306
        # Call URL
1307 1
        response = await self.api_client.delete(url)
1308 1
        assert response.status_code == 409
1309
1310 1
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1311 1
    async def test_delete_schedule_not_found(self, mock_find_evc_by_sched):
1312
        """Test delete a circuit schedule - unexisting."""
1313 1
        mock_find_evc_by_sched.return_value = (None, False)
1314 1
        url = f'{self.base_endpoint}/v2/evc/schedule/1'
1315 1
        response = await self.api_client.delete(url)
1316 1
        assert response.status_code == 404
1317
1318 1
    def test_get_evcs_by_svc_level(self) -> None:
1319
        """Test get_evcs_by_svc_level."""
1320 1
        levels = [1, 2, 4, 2, 7]
1321 1
        evcs = {i: MagicMock(service_level=v, creation_time=1)
1322
                for i, v in enumerate(levels)}
1323 1
        self.napp.circuits = evcs
1324 1
        expected_levels = sorted(levels, reverse=True)
1325 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1326 1
        assert evcs_by_level
1327
1328 1
        for evc, exp_level in zip(evcs_by_level, expected_levels):
1329 1
            assert evc.service_level == exp_level
1330
1331 1
        evcs = {i: MagicMock(service_level=1, creation_time=i)
1332
                for i in reversed(range(2))}
1333 1
        self.napp.circuits = evcs
1334 1
        evcs_by_level = self.napp.get_evcs_by_svc_level()
1335 1
        for i in range(2):
1336 1
            assert evcs_by_level[i].creation_time == i
1337
1338 1
    async def test_get_circuit_not_found(self):
1339
        """Test /v2/evc/<circuit_id> 404."""
1340 1
        self.napp.mongo_controller.get_circuit.return_value = None
1341 1
        url = f'{self.base_endpoint}/v2/evc/1234'
1342 1
        response = await self.api_client.get(url)
1343 1
        assert response.status_code == 404
1344
1345 1
    @patch('requests.post')
1346 1
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1347 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1348 1
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1349 1
    @patch('kytos.core.Controller.get_interface_by_id')
1350 1
    @patch('napps.kytos.mef_eline.models.path.Path.is_valid')
1351 1
    @patch('napps.kytos.mef_eline.models.evc.EVCDeploy.deploy')
1352 1
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1353 1
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1354 1
    async def test_update_circuit(
1355
        self,
1356
        evc_as_dict_mock,
1357
        uni_from_dict_mock,
1358
        evc_deploy,
1359
        _is_valid_mock,
1360
        interface_by_id_mock,
1361
        _mock_validate,
1362
        _mongo_controller_upsert_mock,
1363
        _sched_add_mock,
1364
        requests_mock,
1365
        event_loop,
1366
    ):
1367
        """Test update a circuit circuit."""
1368 1
        self.napp.controller.loop = event_loop
1369 1
        interface_by_id_mock.return_value = get_uni_mocked().interface
1370 1
        unis = [
1371
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:01"),
1372
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:02"),
1373
        ]
1374 1
        uni_from_dict_mock.side_effect = 2 * unis
1375
1376 1
        response = MagicMock()
1377 1
        response.status_code = 201
1378 1
        requests_mock.return_value = response
1379
1380 1
        payloads = [
1381
            {
1382
                "name": "my evc1",
1383
                "uni_a": {
1384
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1385
                    "tag": {"tag_type": 1, "value": 80},
1386
                },
1387
                "uni_z": {
1388
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1389
                    "tag": {"tag_type": 1, "value": 1},
1390
                },
1391
                "dynamic_backup_path": True,
1392
            },
1393
            {
1394
                "primary_path": [
1395
                    {
1396
                        "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1397
                        "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1398
                    }
1399
                ]
1400
            },
1401
            {
1402
                "sb_priority": 3
1403
            },
1404
            {
1405
                # It works only with 'enable' and not with 'enabled'
1406
                "enable": True
1407
            },
1408
            {
1409
                "name": "my evc1",
1410
                "active": True,
1411
                "enable": True,
1412
                "uni_a": {
1413
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1414
                    "tag": {
1415
                        "tag_type": 1,
1416
                        "value": 80
1417
                    }
1418
                },
1419
                "uni_z": {
1420
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1421
                    "tag": {
1422
                        "tag_type": 1,
1423
                        "value": 1
1424
                    }
1425
                },
1426
                "priority": 3,
1427
                "bandwidth": 1000,
1428
                "dynamic_backup_path": True
1429
            }
1430
        ]
1431
1432 1
        evc_as_dict_mock.return_value = payloads[0]
1433 1
        response = await self.api_client.post(
1434
            f"{self.base_endpoint}/v2/evc/",
1435
            json=payloads[0],
1436
        )
1437 1
        assert 201 == response.status_code
1438
1439 1
        evc_deploy.reset_mock()
1440 1
        evc_as_dict_mock.return_value = payloads[1]
1441 1
        current_data = response.json()
1442 1
        circuit_id = current_data["circuit_id"]
1443 1
        response = await self.api_client.patch(
1444
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1445
            json=payloads[1],
1446
        )
1447
        # evc_deploy.assert_called_once()
1448 1
        assert 200 == response.status_code
1449
1450 1
        evc_deploy.reset_mock()
1451 1
        evc_as_dict_mock.return_value = payloads[2]
1452 1
        response = await self.api_client.patch(
1453
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1454
            json=payloads[2],
1455
        )
1456 1
        evc_deploy.assert_not_called()
1457 1
        assert 200 == response.status_code
1458
1459 1
        evc_deploy.reset_mock()
1460 1
        evc_as_dict_mock.return_value = payloads[3]
1461 1
        response = await self.api_client.patch(
1462
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1463
            json=payloads[3],
1464
        )
1465 1
        evc_deploy.assert_called_once()
1466 1
        assert 200 == response.status_code
1467
1468 1
        evc_deploy.reset_mock()
1469 1
        response = await self.api_client.patch(
1470
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1471
            content=b'{"priority":5,}',
1472
            headers={"Content-Type": "application/json"}
1473
        )
1474 1
        evc_deploy.assert_not_called()
1475 1
        assert 400 == response.status_code
1476
1477 1
        response = await self.api_client.patch(
1478
            f"{self.base_endpoint}/v2/evc/1234",
1479
            json=payloads[1],
1480
        )
1481 1
        current_data = response.json()
1482 1
        expected_data = "circuit_id 1234 not found"
1483 1
        assert current_data["description"] == expected_data
1484 1
        assert 404 == response.status_code
1485
1486 1
        await self.api_client.delete(
1487
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1488
        )
1489 1
        evc_deploy.reset_mock()
1490 1
        response = await self.api_client.patch(
1491
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1492
            json=payloads[1],
1493
        )
1494 1
        evc_deploy.assert_not_called()
1495 1
        assert 409 == response.status_code
1496 1
        assert "Can't update archived EVC" in response.json()["description"]
1497
1498 1 View Code Duplication
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1499 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1500 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1501 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1502 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1503 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1504 1
    async def test_update_circuit_invalid_json(
1505
        self,
1506
        evc_as_dict_mock,
1507
        validate_mock,
1508
        mongo_controller_upsert_mock,
1509
        uni_from_dict_mock,
1510
        sched_add_mock,
1511
        evc_deploy_mock,
1512
        event_loop
1513
    ):
1514
        """Test update a circuit circuit."""
1515 1
        self.napp.controller.loop = event_loop
1516 1
        validate_mock.return_value = True
1517 1
        mongo_controller_upsert_mock.return_value = True
1518 1
        sched_add_mock.return_value = True
1519 1
        evc_deploy_mock.return_value = True
1520 1
        uni1 = create_autospec(UNI)
1521 1
        uni2 = create_autospec(UNI)
1522 1
        uni1.interface = create_autospec(Interface)
1523 1
        uni2.interface = create_autospec(Interface)
1524 1
        uni1.interface.switch = MagicMock()
1525 1
        uni1.interface.switch.return_value = "00:00:00:00:00:00:00:01"
1526 1
        uni1.interface.switch.status = EntityStatus.UP
1527 1
        uni2.interface.switch = MagicMock()
1528 1
        uni2.interface.switch.return_value = "00:00:00:00:00:00:00:02"
1529 1
        uni2.interface.switch.status = EntityStatus.UP
1530 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1531
1532 1
        payload1 = {
1533
            "name": "my evc1",
1534
            "uni_a": {
1535
                "interface_id": "00:00:00:00:00:00:00:01:1",
1536
                "tag": {"tag_type": 1, "value": 80},
1537
            },
1538
            "uni_z": {
1539
                "interface_id": "00:00:00:00:00:00:00:02:2",
1540
                "tag": {"tag_type": 1, "value": 1},
1541
            },
1542
            "dynamic_backup_path": True,
1543
        }
1544
1545 1
        payload2 = {
1546
            "dynamic_backup_path": False,
1547
        }
1548
1549 1
        evc_as_dict_mock.return_value = payload1
1550 1
        response = await self.api_client.post(
1551
            f"{self.base_endpoint}/v2/evc/",
1552
            json=payload1
1553
        )
1554 1
        assert 201 == response.status_code
1555
1556 1
        evc_as_dict_mock.return_value = payload2
1557 1
        current_data = response.json()
1558 1
        circuit_id = current_data["circuit_id"]
1559 1
        response = await self.api_client.patch(
1560
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1561
            json=payload2
1562
        )
1563 1
        current_data = response.json()
1564 1
        assert 400 == response.status_code
1565 1
        assert "must have a primary path or" in current_data["description"]
1566
1567 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1568 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1569 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1570 1
    @patch("napps.kytos.mef_eline.main.Main._link_from_dict")
1571 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1572 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1573 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1574 1
    @patch("napps.kytos.mef_eline.models.path.Path.is_valid")
1575 1
    async def test_update_circuit_invalid_path(
1576
        self,
1577
        is_valid_mock,
1578
        evc_as_dict_mock,
1579
        validate_mock,
1580
        mongo_controller_upsert_mock,
1581
        link_from_dict_mock,
1582
        uni_from_dict_mock,
1583
        sched_add_mock,
1584
        evc_deploy_mock,
1585
        event_loop
1586
    ):
1587
        """Test update a circuit circuit."""
1588 1
        self.napp.controller.loop = event_loop
1589 1
        is_valid_mock.side_effect = InvalidPath("error")
1590 1
        validate_mock.return_value = True
1591 1
        mongo_controller_upsert_mock.return_value = True
1592 1
        sched_add_mock.return_value = True
1593 1
        evc_deploy_mock.return_value = True
1594 1
        link_from_dict_mock.return_value = 1
1595 1
        uni1 = create_autospec(UNI)
1596 1
        uni2 = create_autospec(UNI)
1597 1
        uni1.interface = create_autospec(Interface)
1598 1
        uni2.interface = create_autospec(Interface)
1599 1
        uni1.interface.switch = MagicMock()
1600 1
        uni1.interface.switch.return_value = "00:00:00:00:00:00:00:01"
1601 1
        uni1.interface.switch.status = EntityStatus.UP
1602 1
        uni2.interface.switch = MagicMock()
1603 1
        uni2.interface.switch.return_value = "00:00:00:00:00:00:00:02"
1604 1
        uni2.interface.switch.status = EntityStatus.UP
1605 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1606
1607 1
        payload1 = {
1608
            "name": "my evc1",
1609
            "uni_a": {
1610
                "interface_id": "00:00:00:00:00:00:00:01:1",
1611
                "tag": {"tag_type": 1, "value": 80},
1612
            },
1613
            "uni_z": {
1614
                "interface_id": "00:00:00:00:00:00:00:02:2",
1615
                "tag": {"tag_type": 1, "value": 1},
1616
            },
1617
            "dynamic_backup_path": True,
1618
        }
1619
1620 1
        payload2 = {
1621
            "primary_path": [
1622
                {
1623
                    "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1624
                    "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1625
                }
1626
            ]
1627
        }
1628
1629 1
        evc_as_dict_mock.return_value = payload1
1630 1
        response = await self.api_client.post(
1631
            f"{self.base_endpoint}/v2/evc/",
1632
            json=payload1,
1633
        )
1634 1
        assert 201 == response.status_code
1635
1636 1
        evc_as_dict_mock.return_value = payload2
1637 1
        current_data = response.json()
1638 1
        circuit_id = current_data["circuit_id"]
1639 1
        response = await self.api_client.patch(
1640
            f"{self.base_endpoint}/v2/evc/{circuit_id}",
1641
            json=payload2,
1642
        )
1643 1
        current_data = response.json()
1644 1
        expected_data = "primary_path is not a valid path: error"
1645 1
        assert 400 == response.status_code
1646 1
        assert current_data["description"] == expected_data
1647
1648 1
    def test_link_from_dict_non_existent_intf(self):
1649
        """Test _link_from_dict non existent intf."""
1650 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1651 1
        link_dict = {
1652
            "endpoint_a": {"id": "a"},
1653
            "endpoint_b": {"id": "b"}
1654
        }
1655 1
        with pytest.raises(ValueError):
1656 1
            self.napp._link_from_dict(link_dict)
1657
1658 1
    def test_uni_from_dict_non_existent_intf(self):
1659
        """Test _link_from_dict non existent intf."""
1660 1
        self.napp.controller.get_interface_by_id = MagicMock(return_value=None)
1661 1
        uni_dict = {
1662
            "interface_id": "aaa",
1663
        }
1664 1
        with pytest.raises(ValueError):
1665 1
            self.napp._uni_from_dict(uni_dict)
1666
1667 1 View Code Duplication
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1668 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1669 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1670 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1671 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1672 1
    async def test_update_evc_no_json_mime(
1673
        self,
1674
        mongo_controller_upsert_mock,
1675
        validate_mock,
1676
        uni_from_dict_mock,
1677
        sched_add_mock,
1678
        evc_deploy_mock,
1679
        event_loop
1680
    ):
1681
        """Test update a circuit with wrong mimetype."""
1682 1
        self.napp.controller.loop = event_loop
1683 1
        validate_mock.return_value = True
1684 1
        sched_add_mock.return_value = True
1685 1
        evc_deploy_mock.return_value = True
1686 1
        uni1 = create_autospec(UNI)
1687 1
        uni2 = create_autospec(UNI)
1688 1
        uni1.interface = create_autospec(Interface)
1689 1
        uni2.interface = create_autospec(Interface)
1690 1
        uni1.interface.switch = MagicMock()
1691 1
        uni1.interface.switch.return_value = "00:00:00:00:00:00:00:01"
1692 1
        uni1.interface.switch.status = EntityStatus.UP
1693 1
        uni2.interface.switch = MagicMock()
1694 1
        uni2.interface.switch.return_value = "00:00:00:00:00:00:00:02"
1695 1
        uni2.interface.switch.status = EntityStatus.UP
1696 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1697 1
        mongo_controller_upsert_mock.return_value = True
1698
1699 1
        payload1 = {
1700
            "name": "my evc1",
1701
            "uni_a": {
1702
                "interface_id": "00:00:00:00:00:00:00:01:1",
1703
                "tag": {"tag_type": 1, "value": 80},
1704
            },
1705
            "uni_z": {
1706
                "interface_id": "00:00:00:00:00:00:00:02:2",
1707
                "tag": {"tag_type": 1, "value": 1},
1708
            },
1709
            "dynamic_backup_path": True,
1710
        }
1711
1712 1
        payload2 = {"dynamic_backup_path": False}
1713
1714 1
        response = await self.api_client.post(
1715
            f"{self.base_endpoint}/v2/evc/",
1716
            json=payload1,
1717
        )
1718 1
        assert 201 == response.status_code
1719
1720 1
        current_data = response.json()
1721 1
        circuit_id = current_data["circuit_id"]
1722 1
        response = await self.api_client.patch(
1723
            f"{self.base_endpoint}/v2/evc/{circuit_id}", data=payload2
1724
        )
1725 1
        current_data = response.json()
1726 1
        assert 415 == response.status_code
1727 1
        assert "application/json" in current_data["description"]
1728
1729 1
    async def test_delete_no_evc(self):
1730
        """Test delete when EVC does not exist."""
1731 1
        url = f"{self.base_endpoint}/v2/evc/123"
1732 1
        response = await self.api_client.delete(url)
1733 1
        current_data = response.json()
1734 1
        expected_data = "circuit_id 123 not found"
1735 1
        assert current_data["description"] == expected_data
1736 1
        assert 404 == response.status_code
1737
1738 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.remove_current_flows")
1739 1
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1740 1
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1741 1
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1742 1
    @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc")
1743 1
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1744 1
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1745 1
    async def test_delete_archived_evc(
1746
        self,
1747
        evc_as_dict_mock,
1748
        validate_mock,
1749
        mongo_controller_upsert_mock,
1750
        uni_from_dict_mock,
1751
        sched_add_mock,
1752
        evc_deploy_mock,
1753
        remove_current_flows_mock,
1754
        event_loop
1755
    ):
1756
        """Try to delete an archived EVC"""
1757 1
        self.napp.controller.loop = event_loop
1758 1
        validate_mock.return_value = True
1759 1
        mongo_controller_upsert_mock.return_value = True
1760 1
        sched_add_mock.return_value = True
1761 1
        evc_deploy_mock.return_value = True
1762 1
        remove_current_flows_mock.return_value = True
1763 1
        uni1 = create_autospec(UNI)
1764 1
        uni2 = create_autospec(UNI)
1765 1
        uni1.interface = create_autospec(Interface)
1766 1
        uni2.interface = create_autospec(Interface)
1767 1
        uni1.interface.switch = MagicMock()
1768 1
        uni1.interface.switch.return_value = "00:00:00:00:00:00:00:01"
1769 1
        uni1.interface.switch.status = EntityStatus.UP
1770 1
        uni2.interface.switch = MagicMock()
1771 1
        uni2.interface.switch.return_value = "00:00:00:00:00:00:00:02"
1772 1
        uni2.interface.switch.status = EntityStatus.UP
1773 1
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1774
1775 1
        payload1 = {
1776
            "name": "my evc1",
1777
            "uni_a": {
1778
                "interface_id": "00:00:00:00:00:00:00:01:1",
1779
                "tag": {"tag_type": 1, "value": 80},
1780
            },
1781
            "uni_z": {
1782
                "interface_id": "00:00:00:00:00:00:00:02:2",
1783
                "tag": {"tag_type": 1, "value": 1},
1784
            },
1785
            "dynamic_backup_path": True,
1786
        }
1787
1788 1
        evc_as_dict_mock.return_value = payload1
1789 1
        response = await self.api_client.post(
1790
            f"{self.base_endpoint}/v2/evc/",
1791
            json=payload1
1792
        )
1793 1
        assert 201 == response.status_code
1794
1795 1
        current_data = response.json()
1796 1
        circuit_id = current_data["circuit_id"]
1797 1
        response = await self.api_client.delete(
1798
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1799
        )
1800 1
        assert 200 == response.status_code
1801
1802 1
        response = await self.api_client.delete(
1803
            f"{self.base_endpoint}/v2/evc/{circuit_id}"
1804
        )
1805 1
        current_data = response.json()
1806 1
        expected_data = f"Circuit {circuit_id} already removed"
1807 1
        assert current_data["description"] == expected_data
1808 1
        assert 404 == response.status_code
1809
1810 1
    def test_handle_link_up(self):
1811
        """Test handle_link_up method."""
1812 1
        evc_mock = create_autospec(EVC)
1813 1
        evc_mock.service_level, evc_mock.creation_time = 0, 1
1814 1
        evc_mock.is_enabled = MagicMock(side_effect=[True, False, True])
1815 1
        evc_mock.lock = MagicMock()
1816 1
        type(evc_mock).archived = PropertyMock(
1817
            side_effect=[True, False, False]
1818
        )
1819 1
        evcs = [evc_mock, evc_mock, evc_mock]
1820 1
        event = KytosEvent(name="test", content={"link": "abc"})
1821 1
        self.napp.circuits = dict(zip(["1", "2", "3"], evcs))
1822 1
        self.napp.handle_link_up(event)
1823 1
        evc_mock.handle_link_up.assert_called_once_with("abc")
1824
1825 1
    @patch("time.sleep", return_value=None)
1826 1
    @patch("napps.kytos.mef_eline.main.settings")
1827 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1828 1
    def test_handle_link_down(self, emit_event_mock, settings_mock, _):
1829
        """Test handle_link_down method."""
1830 1
        uni = create_autospec(UNI)
1831 1
        evc1 = MagicMock(id="1", service_level=0, creation_time=1,
1832
                         metadata="mock", _active="true", _enabled="true",
1833
                         uni_a=uni, uni_z=uni)
1834 1
        evc1.name = "name"
1835 1
        evc1.is_affected_by_link.return_value = True
1836 1
        evc1.handle_link_down.return_value = True
1837 1
        evc1.failover_path = None
1838 1
        evc2 = MagicMock(id="2", service_level=6, creation_time=1)
1839 1
        evc2.is_affected_by_link.return_value = False
1840 1
        evc3 = MagicMock(id="3", service_level=5, creation_time=1,
1841
                         metadata="mock", _active="true", _enabled="true",
1842
                         uni_a=uni, uni_z=uni)
1843 1
        evc3.name = "name"
1844 1
        evc3.is_affected_by_link.return_value = True
1845 1
        evc3.handle_link_down.return_value = True
1846 1
        evc3.failover_path = None
1847 1
        evc4 = MagicMock(id="4", service_level=4, creation_time=1,
1848
                         metadata="mock", _active="true", _enabled="true",
1849
                         uni_a=uni, uni_z=uni)
1850 1
        evc4.name = "name"
1851 1
        evc4.is_affected_by_link.return_value = True
1852 1
        evc4.is_failover_path_affected_by_link.return_value = False
1853 1
        evc4.failover_path = ["2"]
1854 1
        evc4.get_failover_flows.return_value = {
1855
            "2": ["flow1", "flow2"],
1856
            "3": ["flow3", "flow4", "flow5", "flow6"],
1857
        }
1858 1
        evc5 = MagicMock(id="5", service_level=7, creation_time=1)
1859 1
        evc5.is_affected_by_link.return_value = True
1860 1
        evc5.is_failover_path_affected_by_link.return_value = False
1861 1
        evc5.failover_path = ["3"]
1862 1
        evc5.get_failover_flows.return_value = {
1863
            "4": ["flow7", "flow8"],
1864
            "5": ["flow9", "flow10"],
1865
        }
1866 1
        link = MagicMock(id="123")
1867 1
        event = KytosEvent(name="test", content={"link": link})
1868 1
        self.napp.circuits = {"1": evc1, "2": evc2, "3": evc3, "4": evc4,
1869
                              "5": evc5}
1870 1
        settings_mock.BATCH_SIZE = 2
1871 1
        self.napp.handle_link_down(event)
1872
1873 1
        assert evc5.service_level > evc4.service_level
1874
        # evc5 batched flows should be sent first
1875 1
        emit_event_mock.assert_has_calls([
1876
            call(
1877
                self.napp.controller,
1878
                context="kytos.flow_manager",
1879
                name="flows.install",
1880
                content={
1881
                    "dpid": "4",
1882
                    "flow_dict": {"flows": ["flow7", "flow8"]},
1883
                }
1884
            ),
1885
            call(
1886
                self.napp.controller,
1887
                context="kytos.flow_manager",
1888
                name="flows.install",
1889
                content={
1890
                    "dpid": "5",
1891
                    "flow_dict": {"flows": ["flow9", "flow10"]},
1892
                }
1893
            ),
1894
            call(
1895
                self.napp.controller,
1896
                context="kytos.flow_manager",
1897
                name="flows.install",
1898
                content={
1899
                    "dpid": "2",
1900
                    "flow_dict": {"flows": ["flow1", "flow2"]},
1901
                }
1902
            ),
1903
            call(
1904
                self.napp.controller,
1905
                context="kytos.flow_manager",
1906
                name="flows.install",
1907
                content={
1908
                    "dpid": "3",
1909
                    "flow_dict": {"flows": ["flow3", "flow4"]},
1910
                }
1911
            ),
1912
            call(
1913
                self.napp.controller,
1914
                context="kytos.flow_manager",
1915
                name="flows.install",
1916
                content={
1917
                    "dpid": "3",
1918
                    "flow_dict": {"flows": ["flow5", "flow6"]},
1919
                }
1920
            ),
1921
        ])
1922 1
        event_name = "evc_affected_by_link_down"
1923 1
        assert evc3.service_level > evc1.service_level
1924
        # evc3 should be handled before evc1
1925 1
        emit_event_mock.assert_has_calls([
1926
            call(self.napp.controller, event_name, content={
1927
                "link_id": "123",
1928
                "evc_id": "3",
1929
                "name": "name",
1930
                "metadata": "mock",
1931
                "active": "true",
1932
                "enabled": "true",
1933
                "uni_a": uni.as_dict(),
1934
                "uni_z": uni.as_dict(),
1935
            }),
1936
            call(self.napp.controller, event_name, content={
1937
                "link_id": "123",
1938
                "evc_id": "1",
1939
                "name": "name",
1940
                "metadata": "mock",
1941
                "active": "true",
1942
                "enabled": "true",
1943
                "uni_a": uni.as_dict(),
1944
                "uni_z": uni.as_dict(),
1945
            }),
1946
        ])
1947 1
        evc4.sync.assert_called_once()
1948 1
        event_name = "redeployed_link_down"
1949 1
        emit_event_mock.assert_has_calls([
1950
            call(self.napp.controller, event_name, content={
1951
                "evc_id": "4",
1952
                "name": "name",
1953
                "metadata": "mock",
1954
                "active": "true",
1955
                "enabled": "true",
1956
                "uni_a": uni.as_dict(),
1957
                "uni_z": uni.as_dict(),
1958
            }),
1959
        ])
1960
1961 1
    @patch("napps.kytos.mef_eline.main.emit_event")
1962 1
    def test_handle_evc_affected_by_link_down(self, emit_event_mock):
1963
        """Test handle_evc_affected_by_link_down method."""
1964 1
        uni = create_autospec(UNI)
1965 1
        evc1 = MagicMock(
1966
            id="1",
1967
            metadata="data_mocked",
1968
            _active="true",
1969
            _enabled="false",
1970
            uni_a=uni,
1971
            uni_z=uni,
1972
        )
1973 1
        evc1.name = "name_mocked"
1974 1
        evc1.handle_link_down.return_value = True
1975 1
        evc2 = MagicMock(
1976
            id="2",
1977
            metadata="mocked_data",
1978
            _active="false",
1979
            _enabled="true",
1980
            uni_a=uni,
1981
            uni_z=uni,
1982
        )
1983 1
        evc2.name = "mocked_name"
1984 1
        evc2.handle_link_down.return_value = False
1985 1
        self.napp.circuits = {"1": evc1, "2": evc2}
1986
1987 1
        event = KytosEvent(name="e1", content={
1988
            "evc_id": "3",
1989
            "link_id": "1",
1990
        })
1991 1
        self.napp.handle_evc_affected_by_link_down(event)
1992 1
        emit_event_mock.assert_not_called()
1993 1
        event.content["evc_id"] = "1"
1994 1
        self.napp.handle_evc_affected_by_link_down(event)
1995 1
        emit_event_mock.assert_called_with(
1996
            self.napp.controller, "redeployed_link_down", content={
1997
                "evc_id": "1",
1998
                "name": "name_mocked",
1999
                "metadata": "data_mocked",
2000
                "active": "true",
2001
                "enabled": "false",
2002
                "uni_a": uni.as_dict(),
2003
                "uni_z": uni.as_dict(),
2004
            }
2005
        )
2006
2007 1
        event.content["evc_id"] = "2"
2008 1
        self.napp.handle_evc_affected_by_link_down(event)
2009 1
        emit_event_mock.assert_called_with(
2010
            self.napp.controller, "error_redeploy_link_down", content={
2011
                "evc_id": "2",
2012
                "name": "mocked_name",
2013
                "metadata": "mocked_data",
2014
                "active": "false",
2015
                "enabled": "true",
2016
                "uni_a": uni.as_dict(),
2017
                "uni_z": uni.as_dict(),
2018
            }
2019
        )
2020
2021 1
    def test_handle_evc_deployed(self):
2022
        """Test handle_evc_deployed method."""
2023 1
        evc = create_autospec(EVC, id="1")
2024 1
        evc.lock = MagicMock()
2025 1
        self.napp.circuits = {"1": evc}
2026
2027 1
        event = KytosEvent(name="e1", content={"evc_id": "2"})
2028 1
        self.napp.handle_evc_deployed(event)
2029 1
        evc.setup_failover_path.assert_not_called()
2030
2031 1
        event.content["evc_id"] = "1"
2032 1
        self.napp.handle_evc_deployed(event)
2033 1
        evc.setup_failover_path.assert_called()
2034
2035 1
    async def test_add_metadata(self, event_loop):
2036
        """Test method to add metadata"""
2037 1
        self.napp.controller.loop = event_loop
2038 1
        evc_mock = create_autospec(EVC)
2039 1
        evc_mock.metadata = {}
2040 1
        evc_mock.id = 1234
2041 1
        self.napp.circuits = {"1234": evc_mock}
2042
2043 1
        payload = {"metadata1": 1, "metadata2": 2}
2044 1
        response = await self.api_client.post(
2045
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2046
            json=payload
2047
        )
2048
2049 1
        assert response.status_code == 201
2050 1
        evc_mock.extend_metadata.assert_called_with(payload)
2051
2052 1
    async def test_add_metadata_malformed_json(self, event_loop):
2053
        """Test method to add metadata with a malformed json"""
2054 1
        self.napp.controller.loop = event_loop
2055 1
        payload = b'{"metadata1": 1, "metadata2": 2,}'
2056 1
        response = await self.api_client.post(
2057
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2058
            content=payload,
2059
            headers={"Content-Type": "application/json"}
2060
        )
2061
2062 1
        assert response.status_code == 400
2063 1
        assert "Failed to deserialize" in response.json()["description"]
2064
2065 1
    async def test_add_metadata_no_body(self, event_loop):
2066
        """Test method to add metadata with no body"""
2067 1
        self.napp.controller.loop = event_loop
2068 1
        response = await self.api_client.post(
2069
            f"{self.base_endpoint}/v2/evc/1234/metadata"
2070
        )
2071 1
        assert response.status_code == 400
2072 1
        assert response.json()["description"] == \
2073
            "Missing required request body"
2074
2075 1
    async def test_add_metadata_no_evc(self, event_loop):
2076
        """Test method to add metadata with no evc"""
2077 1
        self.napp.controller.loop = event_loop
2078 1
        payload = {"metadata1": 1, "metadata2": 2}
2079 1
        response = await self.api_client.post(
2080
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2081
            json=payload,
2082
        )
2083 1
        assert response.status_code == 404
2084 1
        assert response.json()["description"] == \
2085
            "circuit_id 1234 not found."
2086
2087 1
    async def test_add_metadata_wrong_content_type(self, event_loop):
2088
        """Test method to add metadata with wrong content type"""
2089 1
        self.napp.controller.loop = event_loop
2090 1
        payload = {"metadata1": 1, "metadata2": 2}
2091 1
        response = await self.api_client.post(
2092
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2093
            data=payload,
2094
            headers={"Content-Type": "application/xml"}
2095
        )
2096 1
        assert response.status_code == 415
2097 1
        assert "application/xml" in response.json()["description"]
2098
2099 1
    async def test_get_metadata(self):
2100
        """Test method to get metadata"""
2101 1
        evc_mock = create_autospec(EVC)
2102 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2103 1
        evc_mock.id = 1234
2104 1
        self.napp.circuits = {"1234": evc_mock}
2105
2106 1
        response = await self.api_client.get(
2107
            f"{self.base_endpoint}/v2/evc/1234/metadata",
2108
        )
2109 1
        assert response.status_code == 200
2110 1
        assert response.json() == {"metadata": evc_mock.metadata}
2111
2112 1
    async def test_delete_metadata(self):
2113
        """Test method to delete metadata"""
2114 1
        evc_mock = create_autospec(EVC)
2115 1
        evc_mock.metadata = {'metadata1': 1, 'metadata2': 2}
2116 1
        evc_mock.id = 1234
2117 1
        self.napp.circuits = {"1234": evc_mock}
2118
2119 1
        response = await self.api_client.delete(
2120
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2121
        )
2122 1
        assert response.status_code == 200
2123
2124 1
    async def test_delete_metadata_no_evc(self):
2125
        """Test method to delete metadata with no evc"""
2126 1
        response = await self.api_client.delete(
2127
            f"{self.base_endpoint}/v2/evc/1234/metadata/metadata1",
2128
        )
2129 1
        assert response.status_code == 404
2130 1
        assert response.json()["description"] == \
2131
            "circuit_id 1234 not found."
2132
2133 1
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
2134 1
    def test_load_all_evcs(self, load_evc_mock):
2135
        """Test load_evcs method"""
2136 1
        mock_circuits = {
2137
            'circuits': {
2138
                1: 'circuit_1',
2139
                2: 'circuit_2',
2140
                3: 'circuit_3',
2141
                4: 'circuit_4'
2142
            }
2143
        }
2144 1
        self.napp.mongo_controller.get_circuits.return_value = mock_circuits
2145 1
        self.napp.circuits = {2: 'circuit_2', 3: 'circuit_3'}
2146 1
        self.napp.load_all_evcs()
2147 1
        load_evc_mock.assert_has_calls([call('circuit_1'), call('circuit_4')])
2148
2149 1
    @patch('napps.kytos.mef_eline.main.Main._evc_from_dict')
2150 1
    def test_load_evc(self, evc_from_dict_mock):
2151
        """Test _load_evc method"""
2152
        # pylint: disable=protected-access
2153
        # case 1: early return with ValueError exception
2154 1
        evc_from_dict_mock.side_effect = ValueError("err")
2155 1
        evc_dict = MagicMock()
2156 1
        assert not self.napp._load_evc(evc_dict)
2157
2158
        # case2: archived evc
2159 1
        evc = MagicMock()
2160 1
        evc.archived = True
2161 1
        evc_from_dict_mock.side_effect = None
2162 1
        evc_from_dict_mock.return_value = evc
2163 1
        assert not self.napp._load_evc(evc_dict)
2164
2165
        # case3: success creating
2166 1
        evc.archived = False
2167 1
        evc.id = 1
2168 1
        self.napp.sched = MagicMock()
2169
2170 1
        result = self.napp._load_evc(evc_dict)
2171 1
        assert result == evc
2172 1
        evc.deactivate.assert_called()
2173 1
        evc.sync.assert_called()
2174 1
        self.napp.sched.add.assert_called_with(evc)
2175 1
        assert self.napp.circuits[1] == evc
2176
2177 1
    def test_handle_flow_mod_error(self):
2178
        """Test handle_flow_mod_error method"""
2179 1
        flow = MagicMock()
2180 1
        flow.cookie = 0xaa00000000000011
2181 1
        event = MagicMock()
2182 1
        event.content = {'flow': flow, 'error_command': 'add'}
2183 1
        evc = create_autospec(EVC)
2184 1
        evc.remove_current_flows = MagicMock()
2185 1
        self.napp.circuits = {"00000000000011": evc}
2186 1
        self.napp.handle_flow_mod_error(event)
2187 1
        evc.remove_current_flows.assert_called_once()
2188
2189 1
    @patch("kytos.core.Controller.get_interface_by_id")
2190 1
    def test_uni_from_dict(self, _get_interface_by_id_mock):
2191
        """Test _uni_from_dict method."""
2192
        # pylint: disable=protected-access
2193
        # case1: early return on empty dict
2194 1
        assert not self.napp._uni_from_dict(None)
2195
2196
        # case2: invalid interface raises ValueError
2197 1
        _get_interface_by_id_mock.return_value = None
2198 1
        uni_dict = {
2199
            "interface_id": "00:01:1",
2200
            "tag": {"tag_type": 1, "value": 81},
2201
        }
2202 1
        with pytest.raises(ValueError):
2203 1
            self.napp._uni_from_dict(uni_dict)
2204
2205
        # case3: success creation
2206 1
        uni_mock = get_uni_mocked(switch_id="00:01")
2207 1
        _get_interface_by_id_mock.return_value = uni_mock.interface
2208 1
        uni = self.napp._uni_from_dict(uni_dict)
2209 1
        assert uni == uni_mock
2210
2211
        # case4: success creation without tag
2212 1
        uni_mock.user_tag = None
2213 1
        del uni_dict["tag"]
2214 1
        uni = self.napp._uni_from_dict(uni_dict)
2215 1
        assert uni == uni_mock
2216
2217 1
    def test_handle_flow_delete(self):
2218
        """Test handle_flow_delete method"""
2219 1
        flow = MagicMock()
2220 1
        flow.cookie = 0xaa00000000000011
2221 1
        event = MagicMock()
2222 1
        event.content = {'flow': flow}
2223 1
        evc = create_autospec(EVC)
2224 1
        evc.set_flow_removed_at = MagicMock()
2225 1
        self.napp.circuits = {"00000000000011": evc}
2226 1
        self.napp.handle_flow_delete(event)
2227 1
        evc.set_flow_removed_at.assert_called_once()
2228
2229 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...
2230
        """Test add_bulk_metadata method"""
2231 1
        self.napp.controller.loop = event_loop
2232 1
        evc_mock = create_autospec(EVC)
2233 1
        evc_mock.id = 1234
2234 1
        self.napp.circuits = {"1234": evc_mock}
2235 1
        payload = {
2236
            "circuit_ids": ["1234"],
2237
            "metadata1": 1,
2238
            "metadata2": 2
2239
        }
2240 1
        response = await self.api_client.post(
2241
            f"{self.base_endpoint}/v2/evc/metadata",
2242
            json=payload
2243
        )
2244 1
        assert response.status_code == 201
2245 1
        args = self.napp.mongo_controller.update_evcs.call_args[0]
2246 1
        ids = payload.pop("circuit_ids")
2247 1
        assert args[0] == ids
2248 1
        assert args[1] == payload
2249 1
        assert args[2] == "add"
2250 1
        calls = self.napp.mongo_controller.update_evcs.call_count
2251 1
        assert calls == 1
2252 1
        evc_mock.extend_metadata.assert_called_with(payload)
2253
2254 1
    async def test_add_bulk_metadata_no_id(self, event_loop):
2255
        """Test add_bulk_metadata with unknown evc id"""
2256 1
        self.napp.controller.loop = event_loop
2257 1
        evc_mock = create_autospec(EVC)
2258 1
        evc_mock.id = 1234
2259 1
        self.napp.circuits = {"1234": evc_mock}
2260 1
        payload = {
2261
            "circuit_ids": ["1234", "4567"]
2262
        }
2263 1
        response = await self.api_client.post(
2264
            f"{self.base_endpoint}/v2/evc/metadata",
2265
            json=payload
2266
        )
2267 1
        assert response.status_code == 404
2268
2269 1
    async def test_add_bulk_metadata_no_circuits(self, event_loop):
2270
        """Test add_bulk_metadata without circuit_ids"""
2271 1
        self.napp.controller.loop = event_loop
2272 1
        evc_mock = create_autospec(EVC)
2273 1
        evc_mock.id = 1234
2274 1
        self.napp.circuits = {"1234": evc_mock}
2275 1
        payload = {
2276
            "metadata": "data"
2277
        }
2278 1
        response = await self.api_client.post(
2279
            f"{self.base_endpoint}/v2/evc/metadata",
2280
            json=payload
2281
        )
2282 1
        assert response.status_code == 400
2283
2284 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...
2285
        """Test delete_metadata method"""
2286 1
        self.napp.controller.loop = event_loop
2287 1
        evc_mock = create_autospec(EVC)
2288 1
        evc_mock.id = 1234
2289 1
        self.napp.circuits = {"1234": evc_mock}
2290 1
        payload = {
2291
            "circuit_ids": ["1234"]
2292
        }
2293 1
        response = await self.api_client.request(
2294
            "DELETE",
2295
            f"{self.base_endpoint}/v2/evc/metadata/metadata1",
2296
            json=payload
2297
        )
2298 1
        assert response.status_code == 200
2299 1
        args = self.napp.mongo_controller.update_evcs.call_args[0]
2300 1
        assert args[0] == payload["circuit_ids"]
2301 1
        assert args[1] == {"metadata1": ""}
2302 1
        assert args[2] == "del"
2303 1
        calls = self.napp.mongo_controller.update_evcs.call_count
2304 1
        assert calls == 1
2305
        assert evc_mock.remove_metadata.call_count == 1
2306