TestMain.test_update_circuit()   B
last analyzed

Complexity

Conditions 1

Size

Total Lines 135
Code Lines 98

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 45
CRAP Score 1.006

Importance

Changes 0
Metric Value
cc 1
eloc 98
nop 12
dl 0
loc 135
ccs 45
cts 55
cp 0.8182
crap 1.006
rs 7.0654
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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