Test Failed
Pull Request — master (#690)
by
unknown
05:06
created

TestMain.test_handle_evc_deployed()   A

Complexity

Conditions 1

Size

Total Lines 39
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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