Passed
Pull Request — master (#184)
by Gleyberson
03:03
created

build.tests.unit.test_main   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 1279
Duplicated Lines 4.93 %

Importance

Changes 0
Metric Value
eloc 922
dl 63
loc 1279
rs 8.798
c 0
b 0
f 0
wmc 41

35 Methods

Rating   Name   Duplication   Size   Complexity  
B TestMain.test_update_circuit_invalid_json() 0 54 1
A TestMain.test_list_no_circuits_stored() 0 12 1
B TestMain.test_create_schedule() 0 48 1
A TestMain._uni_from_dict_side_effect() 0 5 1
A TestMain.test_circuit_with_invalid_id() 12 12 1
B TestMain._add_storehouse_schedule_data() 0 86 1
B TestMain.test_load_circuits_by_interface() 0 189 1
A TestMain.test_handle_link_down() 0 10 1
A TestMain.test_list_with_archived_circuits_stored_1() 13 13 1
B TestMain.test_update_schedule() 0 69 1
A TestMain.test_circuit_with_valid_id() 12 12 1
A TestMain.test_list_with_archived_circuits_stored_2() 13 13 1
B TestMain.test_delete_schedule() 0 55 1
B TestMain.test_update_circuit() 0 104 2
A TestMain.test_evc_from_dict_paths() 0 47 1
A TestMain.get_app_test_client() 0 5 1
B TestMain.test_create_circuit_already_enabled() 0 54 1
B TestMain.test_create_a_circuit_case_1() 0 65 1
A TestMain.get_napp_urls() 0 24 4
A TestMain.test_list_schedules_from_storehouse() 0 30 1
A TestMain.test_verify_api_urls() 0 35 1
A TestMain.test_list_without_circuits() 0 7 1
A TestMain.test_delete_schedule_archived() 0 35 1
A TestMain.test_list_schedules__no_data_stored() 0 14 1
A TestMain.test_get_specific_schedule_from_storehouse() 0 19 1
A TestMain.test_get_specific_schedules_from_storehouse_not_found() 0 13 1
A TestMain.test_handle_link_up() 0 11 1
A TestMain.test_get_event_listeners() 0 10 2
A TestMain.test_update_schedule_archived() 0 45 1
A TestMain.test_list_schedules__no_data() 0 7 1
A TestMain.test_list_with_circuits_stored() 13 13 1
A TestMain.test_evc_from_dict() 0 38 1
A TestMain.test_evc_from_dict_links() 0 46 1
A TestMain.test_create_a_circuit_case_2() 0 11 1
A TestMain.setUp() 0 16 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

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

Common duplication problems, and corresponding solutions are:

Complexity

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

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

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

1
"""Module to test the main napp file."""
2
import json
3
from unittest import TestCase
4
from unittest.mock import MagicMock, PropertyMock, patch, create_autospec, call
5
6
from kytos.core.interface import UNI, Interface
7
from kytos.core.events import KytosEvent
8
9
from napps.kytos.mef_eline.models import EVC
10
from tests.helpers import get_controller_mock
11
12
13
# pylint: disable=too-many-public-methods, too-many-lines
14
class TestMain(TestCase):
15
    """Test the Main class."""
16
17
    def setUp(self):
18
        """Execute steps before each tests.
19
20
        Set the server_name_url_url from kytos/mef_eline
21
        """
22
        self.server_name_url = 'http://localhost:8181/api/kytos/mef_eline'
23
24
        # The decorator run_on_thread is patched, so methods that listen
25
        # for events do not run on threads while tested.
26
        # Decorators have to be patched before the methods that are
27
        # decorated with them are imported.
28
        patch('kytos.core.helpers.run_on_thread', lambda x: x).start()
29
        from napps.kytos.mef_eline.main import Main
30
31
        self.addCleanup(patch.stopall)
32
        self.napp = Main(get_controller_mock())
33
34
    def test_get_event_listeners(self):
35
        """Verify all event listeners registered."""
36
        expected_events = ['kytos/core.shutdown',
37
                           'kytos/core.shutdown.kytos/mef_eline',
38
                           'kytos/topology.link_up',
39
                           'kytos/topology.link_down']
40
        actual_events = self.napp.listeners()
41
42
        for _event in expected_events:
43
            self.assertIn(_event, actual_events, '%s' % _event)
44
45
    def test_verify_api_urls(self):
46
        """Verify all APIs registered."""
47
        expected_urls = [
48
            ({}, {'POST', 'OPTIONS'},
49
             '/api/kytos/mef_eline/v2/evc/'),
50
51
            ({}, {'OPTIONS', 'HEAD', 'GET'},
52
             '/api/kytos/mef_eline/v2/evc/'),
53
54
            ({'circuit_id': '[circuit_id]'}, {'OPTIONS', 'DELETE'},
55
             '/api/kytos/mef_eline/v2/evc/<circuit_id>'),
56
57
            ({'circuit_id': '[circuit_id]'}, {'OPTIONS', 'HEAD', 'GET'},
58
             '/api/kytos/mef_eline/v2/evc/<circuit_id>'),
59
60
            ({'circuit_id': '[circuit_id]'}, {'OPTIONS', 'PATCH'},
61
             '/api/kytos/mef_eline/v2/evc/<circuit_id>'),
62
63
            ({}, {'OPTIONS', 'GET', 'HEAD'},
64
             '/api/kytos/mef_eline/v2/evc/schedule'),
65
66
            ({}, {'POST', 'OPTIONS'},
67
             '/api/kytos/mef_eline/v2/evc/schedule/'),
68
69
            ({'schedule_id': '[schedule_id]'},
70
             {'OPTIONS', 'DELETE'},
71
             '/api/kytos/mef_eline/v2/evc/schedule/<schedule_id>'),
72
73
            ({'schedule_id': '[schedule_id]'},
74
             {'OPTIONS', 'PATCH'},
75
             '/api/kytos/mef_eline/v2/evc/schedule/<schedule_id>')
76
            ]
77
78
        urls = self.get_napp_urls(self.napp)
79
        self.assertCountEqual(expected_urls, urls)
80
81
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
82
    @patch('napps.kytos.mef_eline.models.EVCBase._validate')
83
    def test_evc_from_dict(self, _validate_mock, uni_from_dict_mock):
84
        """
85
        Test the helper method that create an EVN from dict.
86
87
        Verify object creation with circuit data and schedule data.
88
        """
89
        _validate_mock.return_value = True
90
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
91
        payload = {
92
            "name": "my evc1",
93
            "uni_a": {
94
                "interface_id": "00:00:00:00:00:00:00:01:1",
95
                "tag": {
96
                    "tag_type": 1,
97
                    "value": 80
98
                }
99
            },
100
            "uni_z": {
101
                "interface_id": "00:00:00:00:00:00:00:02:2",
102
                "tag": {
103
                    "tag_type": 1,
104
                    "value": 1
105
                }
106
            },
107
            "circuit_scheduler": [{
108
                "frequency": "* * * * *",
109
                "action": "create"
110
            }]
111
        }
112
        # pylint: disable=protected-access
113
        evc_response = self.napp._evc_from_dict(payload)
114
        self.assertIsNotNone(evc_response)
115
        self.assertIsNotNone(evc_response.uni_a)
116
        self.assertIsNotNone(evc_response.uni_z)
117
        self.assertIsNotNone(evc_response.circuit_scheduler)
118
        self.assertIsNotNone(evc_response.name)
119
120
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
121
    @patch('napps.kytos.mef_eline.models.EVCBase._validate')
122
    @patch('kytos.core.Controller.get_interface_by_id')
123
    def test_evc_from_dict_paths(self, _get_interface_by_id_mock,
124
                                 _validate_mock, uni_from_dict_mock):
125
        """
126
        Test the helper method that create an EVN from dict.
127
128
        Verify object creation with circuit data and schedule data.
129
        """
130
        _get_interface_by_id_mock.return_value = True
131
        _validate_mock.return_value = True
132
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
133
        payload = {
134
            "name": "my evc1",
135
            "uni_a": {
136
                "interface_id": "00:00:00:00:00:00:00:01:1",
137
                "tag": {
138
                    "tag_type": 1,
139
                    "value": 80
140
                }
141
            },
142
            "uni_z": {
143
                "interface_id": "00:00:00:00:00:00:00:02:2",
144
                "tag": {
145
                    "tag_type": 1,
146
                    "value": 1
147
                }
148
            },
149
            "current_path": [],
150
            "primary_path": [
151
                {"endpoint_a": {"interface_id": "00:00:00:00:00:00:00:01:1"},
152
                 "endpoint_b": {"interface_id": "00:00:00:00:00:00:00:02:2"}}
153
            ],
154
            "backup_path": []
155
        }
156
157
        # pylint: disable=protected-access
158
        evc_response = self.napp._evc_from_dict(payload)
159
        self.assertIsNotNone(evc_response)
160
        self.assertIsNotNone(evc_response.uni_a)
161
        self.assertIsNotNone(evc_response.uni_z)
162
        self.assertIsNotNone(evc_response.circuit_scheduler)
163
        self.assertIsNotNone(evc_response.name)
164
        self.assertEqual(len(evc_response.current_path), 0)
165
        self.assertEqual(len(evc_response.backup_path), 0)
166
        self.assertEqual(len(evc_response.primary_path), 1)
167
168
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
169
    @patch('napps.kytos.mef_eline.models.EVCBase._validate')
170
    @patch('kytos.core.Controller.get_interface_by_id')
171
    def test_evc_from_dict_links(self, _get_interface_by_id_mock,
172
                                 _validate_mock, uni_from_dict_mock):
173
        """
174
        Test the helper method that create an EVN from dict.
175
176
        Verify object creation with circuit data and schedule data.
177
        """
178
        _get_interface_by_id_mock.return_value = True
179
        _validate_mock.return_value = True
180
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
181
        payload = {
182
            "name": "my evc1",
183
            "uni_a": {
184
                "interface_id": "00:00:00:00:00:00:00:01:1",
185
                "tag": {
186
                    "tag_type": 1,
187
                    "value": 80
188
                }
189
            },
190
            "uni_z": {
191
                "interface_id": "00:00:00:00:00:00:00:02:2",
192
                "tag": {
193
                    "tag_type": 1,
194
                    "value": 1
195
                }
196
            },
197
            "primary_links": [
198
                {"endpoint_a": {"interface_id": "00:00:00:00:00:00:00:01:1"},
199
                 "endpoint_b": {"interface_id": "00:00:00:00:00:00:00:02:2"}}
200
            ],
201
            "backup_links": []
202
        }
203
204
        # pylint: disable=protected-access
205
        evc_response = self.napp._evc_from_dict(payload)
206
        self.assertIsNotNone(evc_response)
207
        self.assertIsNotNone(evc_response.uni_a)
208
        self.assertIsNotNone(evc_response.uni_z)
209
        self.assertIsNotNone(evc_response.circuit_scheduler)
210
        self.assertIsNotNone(evc_response.name)
211
        self.assertEqual(len(evc_response.current_links_cache), 0)
212
        self.assertEqual(len(evc_response.backup_links), 0)
213
        self.assertEqual(len(evc_response.primary_links), 1)
214
215
    def test_list_without_circuits(self):
216
        """Test if list circuits return 'no circuit stored.'."""
217
        api = self.get_app_test_client(self.napp)
218
        url = f'{self.server_name_url}/v2/evc/'
219
        response = api.get(url)
220
        self.assertEqual(response.status_code, 200, response.data)
221
        self.assertEqual(json.loads(response.data.decode()), {})
222
223
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
224
    def test_list_no_circuits_stored(self, storehouse_data_mock):
225
        """Test if list circuits return all circuits stored."""
226
        circuits = {}
227
        storehouse_data_mock.return_value = circuits
228
229
        api = self.get_app_test_client(self.napp)
230
        url = f'{self.server_name_url}/v2/evc/'
231
232
        response = api.get(url)
233
        expected_result = circuits
234
        self.assertEqual(json.loads(response.data), expected_result)
235
236 View Code Duplication
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
237
    def test_list_with_circuits_stored(self, storehouse_data_mock):
238
        """Test if list circuits return all circuits stored."""
239
        circuits = {'1': {'name': 'circuit_1'},
240
                    '2': {'name': 'circuit_2'}}
241
        storehouse_data_mock.return_value = circuits
242
243
        api = self.get_app_test_client(self.napp)
244
        url = f'{self.server_name_url}/v2/evc/'
245
246
        response = api.get(url)
247
        expected_result = circuits
248
        self.assertEqual(json.loads(response.data), expected_result)
249
250 View Code Duplication
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
251
    def test_list_with_archived_circuits_stored_1(self, storehouse_data_mock):
252
        """Test if list circuits return only circuits not archived."""
253
        circuits = {'1': {'name': 'circuit_1'},
254
                    '2': {'name': 'circuit_2', 'archived': True}}
255
        storehouse_data_mock.return_value = circuits
256
257
        api = self.get_app_test_client(self.napp)
258
        url = f'{self.server_name_url}/v2/evc/'
259
260
        response = api.get(url)
261
        expected_result = {'1': circuits['1']}
262
        self.assertEqual(json.loads(response.data), expected_result)
263
264 View Code Duplication
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
265
    def test_list_with_archived_circuits_stored_2(self, storehouse_data_mock):
266
        """Test if list circuits return all circuits."""
267
        circuits = {'1': {'name': 'circuit_1'},
268
                    '2': {'name': 'circuit_2', 'archived': True}}
269
        storehouse_data_mock.return_value = circuits
270
271
        api = self.get_app_test_client(self.napp)
272
        url = f'{self.server_name_url}/v2/evc/?archived=True'
273
274
        response = api.get(url)
275
        expected_result = circuits
276
        self.assertEqual(json.loads(response.data), expected_result)
277
278 View Code Duplication
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
279
    def test_circuit_with_valid_id(self, storehouse_data_mock):
280
        """Test if get_circuit return the circuit attributes."""
281
        circuits = {'1': {'name': 'circuit_1'},
282
                    '2': {'name': 'circuit_2'}}
283
        storehouse_data_mock.return_value = circuits
284
285
        api = self.get_app_test_client(self.napp)
286
        url = f'{self.server_name_url}/v2/evc/1'
287
        response = api.get(url)
288
        expected_result = circuits['1']
289
        self.assertEqual(json.loads(response.data), expected_result)
290
291 View Code Duplication
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
292
    def test_circuit_with_invalid_id(self, storehouse_data_mock):
293
        """Test if get_circuit return invalid circuit_id."""
294
        circuits = {'1': {'name': 'circuit_1'},
295
                    '2': {'name': 'circuit_2'}}
296
        storehouse_data_mock.return_value = circuits
297
298
        api = self.get_app_test_client(self.napp)
299
        url = f'{self.server_name_url}/v2/evc/3'
300
        response = api.get(url)
301
        expected_result = {'response': 'circuit_id 3 not found'}
302
        self.assertEqual(json.loads(response.data), expected_result)
303
304
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
305
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
306
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
307
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
308
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
309
    @patch('napps.kytos.mef_eline.models.EVC._validate')
310
    def test_create_a_circuit_case_1(self, *args):
311
        """Test create a new circuit."""
312
        (validate_mock, evc_as_dict_mock, save_evc_mock,
313
         uni_from_dict_mock, sched_add_mock, storehouse_data_mock) = args
314
315
        validate_mock.return_value = True
316
        save_evc_mock.return_value = True
317
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
318
        evc_as_dict_mock.return_value = {}
319
        sched_add_mock.return_value = True
320
        storehouse_data_mock.return_value = {}
321
322
        api = self.get_app_test_client(self.napp)
323
        url = f'{self.server_name_url}/v2/evc/'
324
        payload = {
325
                   "name": "my evc1",
326
                   "frequency": "* * * * *",
327
                   "uni_a": {
328
                     "interface_id": "00:00:00:00:00:00:00:01:1",
329
                     "tag": {
330
                       "tag_type": 1,
331
                       "value": 80
332
                     }
333
                   },
334
                   "uni_z": {
335
                     "interface_id": "00:00:00:00:00:00:00:02:2",
336
                     "tag": {
337
                       "tag_type": 1,
338
                       "value": 1
339
                     }
340
                   }
341
                 }
342
343
        response = api.post(url, data=json.dumps(payload),
344
                            content_type='application/json')
345
        current_data = json.loads(response.data)
346
347
        # verify expected result from request
348
        self.assertEqual(201, response.status_code, response.data)
349
        self.assertIn('circuit_id', current_data)
350
351
        # verify uni called
352
        uni_from_dict_mock.called_twice()
353
        uni_from_dict_mock.assert_any_call(payload['uni_z'])
354
        uni_from_dict_mock.assert_any_call(payload['uni_a'])
355
356
        # verify validation called
357
        validate_mock.assert_called_once()
358
        validate_mock.assert_called_with(frequency='* * * * *',
359
                                         name='my evc1',
360
                                         uni_a='uni_a',
361
                                         uni_z='uni_z')
362
        # verify save method is called
363
        save_evc_mock.assert_called_once()
364
365
        # verify evc as dict is called to save in the box
366
        evc_as_dict_mock.assert_called_once()
367
        # verify add circuit in sched
368
        sched_add_mock.assert_called_once()
369
370
    @staticmethod
371
    def get_napp_urls(napp):
372
        """Return the kytos/mef_eline urls.
373
374
        The urls will be like:
375
376
        urls = [
377
            (options, methods, url)
378
        ]
379
380
        """
381
        controller = napp.controller
382
        controller.api_server.register_napp_endpoints(napp)
383
384
        urls = []
385
        for rule in controller.api_server.app.url_map.iter_rules():
386
            options = {}
387
            for arg in rule.arguments:
388
                options[arg] = "[{0}]".format(arg)
389
390
            if f'{napp.username}/{napp.name}' in str(rule):
391
                urls.append((options, rule.methods, f'{str(rule)}'))
392
393
        return urls
394
395
    @staticmethod
396
    def get_app_test_client(napp):
397
        """Return a flask api test client."""
398
        napp.controller.api_server.register_napp_endpoints(napp)
399
        return napp.controller.api_server.app.test_client()
400
401
    def test_create_a_circuit_case_2(self):
402
        """Test create a new circuit trying to send request without a json."""
403
        api = self.get_app_test_client(self.napp)
404
        url = f'{self.server_name_url}/v2/evc/'
405
406
        response = api.post(url)
407
        current_data = json.loads(response.data)
408
        expected_data = 'Bad request: The request do not have a json.'
409
410
        self.assertEqual(400, response.status_code, response.data)
411
        self.assertEqual(current_data, expected_data)
412
413
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
414
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
415
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
416
    @patch('napps.kytos.mef_eline.models.EVC._validate')
417
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
418
    def test_create_circuit_already_enabled(self, *args):
419
        """Test create an already created circuit."""
420
        (evc_as_dict_mock, validate_mock, save_evc_mock,
421
         uni_from_dict_mock, sched_add_mock) = args
422
423
        validate_mock.return_value = True
424
        save_evc_mock.return_value = True
425
        sched_add_mock.return_value = True
426
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z', 'uni_a', 'uni_z']
427
        payload1 = {'name': 'circuit_1'}
428
429
        api = self.get_app_test_client(self.napp)
430
        payload2 = {
431
            "name": "my evc1",
432
            "uni_a": {
433
                "interface_id": "00:00:00:00:00:00:00:01:1",
434
                "tag": {
435
                    "tag_type": 1,
436
                    "value": 80
437
                }
438
            },
439
            "uni_z": {
440
                "interface_id": "00:00:00:00:00:00:00:02:2",
441
                "tag": {
442
                    "tag_type": 1,
443
                    "value": 1
444
                }
445
            }
446
        }
447
448
        evc_as_dict_mock.return_value = payload1
449
        response = api.post(f'{self.server_name_url}/v2/evc/',
450
                            data=json.dumps(payload1),
451
                            content_type='application/json')
452
        self.assertEqual(201, response.status_code)
453
454
        evc_as_dict_mock.return_value = payload2
455
        response = api.post(f'{self.server_name_url}/v2/evc/',
456
                            data=json.dumps(payload2),
457
                            content_type='application/json')
458
        self.assertEqual(201, response.status_code)
459
460
        response = api.post(f'{self.server_name_url}/v2/evc/',
461
                            data=json.dumps(payload2),
462
                            content_type='application/json')
463
        current_data = json.loads(response.data)
464
        expected_data = 'Not Acceptable: This evc already exists.'
465
        self.assertEqual(current_data, expected_data)
466
        self.assertEqual(409, response.status_code)
467
468
    def test_load_circuits_by_interface(self):
469
        """Test if existing circuits are correctly loaded to the cache."""
470
        stored_circuits = {
471
            "182f5bac84074017a262a2321195dbb4": {
472
                "active": False,
473
                "archived": True,
474
                "backup_links": [],
475
                "backup_path": [],
476
                "bandwidth": 0,
477
                "circuit_scheduler": [
478
                    {
479
                        "action": "create",
480
                        "frequency": "*/3 * * * *",
481
                        "id": "db7f8a301e2b4ff69a2ad9a6267430e2"
482
                    },
483
                    {
484
                        "action": "remove",
485
                        "frequency": "2-59/3 * * * *",
486
                        "id": "b8a8bbe85bc144b0afc65181e4c069a1"
487
                    }
488
                ],
489
                "creation_time": "2019-08-09T19:25:06",
490
                "current_path": [],
491
                "dynamic_backup_path": True,
492
                "enabled": False,
493
                "end_date": "2018-12-29T15:16:50",
494
                "id": "182f5bac84074017a262a2321195dbb4",
495
                "name": "Teste2",
496
                "owner": None,
497
                "primary_links": [],
498
                "primary_path": [],
499
                "priority": 0,
500
                "request_time": "2019-08-09T19:25:06",
501
                "start_date": "2019-08-09T19:25:06",
502
                "uni_a": {
503
                    "interface_id": "00:00:00:00:00:00:00:03:12",
504
                    "tag": {
505
                        "tag_type": 1,
506
                        "value": 321
507
                    }
508
                },
509
                "uni_z": {
510
                    "interface_id": "00:00:00:00:00:00:00:06:11",
511
                    "tag": {
512
                        "tag_type": 1,
513
                        "value": 612
514
                    }
515
                }
516
            },
517
            "65c4582cc8f249c2a5947ef500c19e37": {
518
                "active": False,
519
                "archived": False,
520
                "backup_links": [],
521
                "backup_path": [],
522
                "bandwidth": 0,
523
                "circuit_scheduler": [
524
                    {
525
                        "action": "create",
526
                        "frequency": "*/3 * * * *",
527
                        "id": "0939dedf66ce431f85beb53daf578d73"
528
                    },
529
                    {
530
                        "action": "remove",
531
                        "frequency": "2-59/3 * * * *",
532
                        "id": "6cdcab31a11f44708e23776b4dad7893"
533
                    }
534
                ],
535
                "creation_time": "2019-07-22T16:01:24",
536
                "current_path": [],
537
                "dynamic_backup_path": True,
538
                "enabled": False,
539
                "end_date": "2018-12-29T15:16:50",
540
                "id": "65c4582cc8f249c2a5947ef500c19e37",
541
                "name": "Teste2",
542
                "owner": None,
543
                "primary_links": [],
544
                "primary_path": [
545
                    {
546
                        "active": False,
547
                        "enabled": True,
548
                        "endpoint_a": {
549
                            "active": False,
550
                            "enabled": True,
551
                            "id": "00:00:00:00:00:00:00:03:3",
552
                            "link": "0e2b5d7bc858b9f38db11b69",
553
                            "mac": "ae:6e:d3:96:83:5a",
554
                            "metadata": {},
555
                            "name": "s3-eth3",
556
                            "nni": True,
557
                            "port_number": 3,
558
                            "speed": 1250000000.0,
559
                            "switch": "00:00:00:00:00:00:00:03",
560
                            "type": "interface",
561
                            "uni": False
562
                        },
563
                        "endpoint_b": {
564
                            "active": False,
565
                            "enabled": True,
566
                            "id": "00:00:00:00:00:00:00:05:2",
567
                            "link": "0e2b5d7bc858b9f38db11b69",
568
                            "mac": "de:eb:d0:b0:14:cf",
569
                            "metadata": {},
570
                            "name": "s5-eth2",
571
                            "nni": True,
572
                            "port_number": 2,
573
                            "speed": 1250000000.0,
574
                            "switch": "00:00:00:00:00:00:00:05",
575
                            "type": "interface",
576
                            "uni": False
577
                        },
578
                        "id": "0e2b5d7bc858b9f38db11b69",
579
                        "metadata": {}
580
                    },
581
                    {
582
                        "active": False,
583
                        "enabled": True,
584
                        "endpoint_a": {
585
                            "active": False,
586
                            "enabled": True,
587
                            "id": "00:00:00:00:00:00:00:05:4",
588
                            "link": "53bd36ff55a5aa2029bd5d50",
589
                            "mac": "6e:c2:ea:c4:18:12",
590
                            "metadata": {},
591
                            "name": "s5-eth4",
592
                            "nni": True,
593
                            "port_number": 4,
594
                            "speed": 1250000000.0,
595
                            "switch": "00:00:00:00:00:00:00:05",
596
                            "type": "interface",
597
                            "uni": False
598
                        },
599
                        "endpoint_b": {
600
                            "active": False,
601
                            "enabled": True,
602
                            "id": "00:00:00:00:00:00:00:06:2",
603
                            "link": "53bd36ff55a5aa2029bd5d50",
604
                            "mac": "5a:25:7b:7c:0d:ac",
605
                            "metadata": {},
606
                            "name": "s6-eth2",
607
                            "nni": True,
608
                            "port_number": 2,
609
                            "speed": 1250000000.0,
610
                            "switch": "00:00:00:00:00:00:00:06",
611
                            "type": "interface",
612
                            "uni": False
613
                        },
614
                        "id": "53bd36ff55a5aa2029bd5d50",
615
                        "metadata": {}
616
                    }
617
                ],
618
                "priority": 0,
619
                "request_time": "2019-07-22T16:01:24",
620
                "start_date": "2019-07-22T16:01:24",
621
                "uni_a": {
622
                    "interface_id": "00:00:00:00:00:00:00:03:12",
623
                    "tag": {
624
                        "tag_type": 1,
625
                        "value": 321
626
                    }
627
                },
628
                "uni_z": {
629
                    "interface_id": "00:00:00:00:00:00:00:06:11",
630
                    "tag": {
631
                        "tag_type": 1,
632
                        "value": 612
633
                    }
634
                }
635
            }
636
        }
637
638
        expected_result = {
639
            '00:00:00:00:00:00:00:03:12':
640
                {'182f5bac84074017a262a2321195dbb4',
641
                 '65c4582cc8f249c2a5947ef500c19e37'},
642
            '00:00:00:00:00:00:00:06:11':
643
                {'182f5bac84074017a262a2321195dbb4',
644
                 '65c4582cc8f249c2a5947ef500c19e37'},
645
            '00:00:00:00:00:00:00:03:3':
646
                {'65c4582cc8f249c2a5947ef500c19e37'},
647
            '00:00:00:00:00:00:00:05:2':
648
                {'65c4582cc8f249c2a5947ef500c19e37'},
649
            '00:00:00:00:00:00:00:05:4':
650
                {'65c4582cc8f249c2a5947ef500c19e37'},
651
            '00:00:00:00:00:00:00:06:2':
652
                {'65c4582cc8f249c2a5947ef500c19e37'}
653
        }
654
        self.napp.load_circuits_by_interface(stored_circuits)
655
        # pylint: disable=protected-access
656
        self.assertEqual(self.napp._circuits_by_interface, expected_result)
657
658
    def test_list_schedules__no_data(self):
659
        """Test list of schedules."""
660
        api = self.get_app_test_client(self.napp)
661
        url = f'{self.server_name_url}/v2/evc/schedule'
662
        response = api.get(url)
663
        self.assertEqual(response.status_code, 200, response.data)
664
        self.assertEqual(json.loads(response.data.decode()), {})
665
666
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
667
    def test_list_schedules__no_data_stored(self, storehouse_data_mock):
668
        """Test if list circuits return all circuits stored."""
669
        circuits = {}
670
        storehouse_data_mock.return_value = circuits
671
672
        api = self.get_app_test_client(self.napp)
673
        url = f'{self.server_name_url}/v2/evc/schedule'
674
675
        response = api.get(url)
676
        expected_result = circuits
677
678
        self.assertEqual(response.status_code, 200, response.data)
679
        self.assertEqual(json.loads(response.data), expected_result)
680
681
    # pylint: disable=no-self-use
682
    def _add_storehouse_schedule_data(self, storehouse_data_mock):
683
        """Add schedule data to storehouse mock object."""
684
        circuits = {}
685
        payload_1 = {
686
            "id": "aa:aa:aa",
687
            "name": "my evc1",
688
            "uni_a": {
689
                "interface_id": "00:00:00:00:00:00:00:01:1",
690
                "tag": {
691
                    "tag_type": 1,
692
                    "value": 80
693
                }
694
            },
695
            "uni_z": {
696
                "interface_id": "00:00:00:00:00:00:00:02:2",
697
                "tag": {
698
                    "tag_type": 1,
699
                    "value": 1
700
                }
701
            },
702
            "circuit_scheduler": [
703
                {
704
                    "id": "1",
705
                    "frequency": "* * * * *",
706
                    "action": "create"
707
                },
708
                {
709
                    "id": "2",
710
                    "frequency": "1 * * * *",
711
                    "action": "remove"
712
                }
713
            ]
714
        }
715
        circuits.update({"aa:aa:aa": payload_1})
716
        payload_2 = {
717
            "id": "bb:bb:bb",
718
            "name": "my second evc2",
719
            "uni_a": {
720
                "interface_id": "00:00:00:00:00:00:00:01:2",
721
                "tag": {
722
                    "tag_type": 1,
723
                    "value": 90
724
                }
725
            },
726
            "uni_z": {
727
                "interface_id": "00:00:00:00:00:00:00:03:2",
728
                "tag": {
729
                    "tag_type": 1,
730
                    "value": 100
731
                }
732
            },
733
            "circuit_scheduler": [
734
                {
735
                    "id": "3",
736
                    "frequency": "1 * * * *",
737
                    "action": "create"
738
                },
739
                {
740
                    "id": "4",
741
                    "frequency": "2 * * * *",
742
                    "action": "remove"
743
                }
744
            ]
745
        }
746
        circuits.update({"bb:bb:bb": payload_2})
747
        payload_3 = {
748
            "id": "cc:cc:cc",
749
            "name": "my third evc3",
750
            "uni_a": {
751
                "interface_id": "00:00:00:00:00:00:00:03:1",
752
                "tag": {
753
                    "tag_type": 1,
754
                    "value": 90
755
                }
756
            },
757
            "uni_z": {
758
                "interface_id": "00:00:00:00:00:00:00:04:2",
759
                "tag": {
760
                    "tag_type": 1,
761
                    "value": 100
762
                }
763
            }
764
        }
765
        circuits.update({"cc:cc:cc": payload_3})
766
        # Add one circuit to the storehouse.
767
        storehouse_data_mock.return_value = circuits
768
769
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
770
    def test_list_schedules_from_storehouse(self, storehouse_data_mock):
771
        """Test if list circuits return specific circuits stored."""
772
        self._add_storehouse_schedule_data(storehouse_data_mock)
773
774
        api = self.get_app_test_client(self.napp)
775
        url = f'{self.server_name_url}/v2/evc/schedule'
776
777
        # Call URL
778
        response = api.get(url)
779
        # Expected JSON data from response
780
        expected = [{'circuit_id': 'aa:aa:aa',
781
                     'schedule': {'action': 'create',
782
                                  'frequency': '* * * * *', 'id': '1'},
783
                     'schedule_id': '1'},
784
                    {'circuit_id': 'aa:aa:aa',
785
                     'schedule': {'action': 'remove',
786
                                  'frequency': '1 * * * *', 'id': '2'},
787
                     'schedule_id': '2'},
788
                    {'circuit_id': 'bb:bb:bb',
789
                     'schedule': {'action': 'create',
790
                                  'frequency': '1 * * * *', 'id': '3'},
791
                     'schedule_id': '3'},
792
                    {'circuit_id': 'bb:bb:bb',
793
                     'schedule': {'action': 'remove',
794
                                  'frequency': '2 * * * *', 'id': '4'},
795
                     'schedule_id': '4'}]
796
797
        self.assertEqual(response.status_code, 200, response.data)
798
        self.assertEqual(expected, json.loads(response.data))
799
800
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
801
    def test_get_specific_schedule_from_storehouse(self, storehouse_data_mock):
802
        """Test get schedules from a circuit."""
803
        self._add_storehouse_schedule_data(storehouse_data_mock)
804
805
        requested_circuit_id = "bb:bb:bb"
806
        api = self.get_app_test_client(self.napp)
807
        url = f'{self.server_name_url}/v2/evc/{requested_circuit_id}'
808
809
        # Call URL
810
        response = api.get(url)
811
812
        # Expected JSON data from response
813
        expected = [{'action': 'create', 'frequency': '1 * * * *', 'id': '3'},
814
                    {'action': 'remove', 'frequency': '2 * * * *', 'id': '4'}]
815
816
        self.assertEqual(response.status_code, 200)
817
        self.assertEqual(expected,
818
                         json.loads(response.data)["circuit_scheduler"])
819
820
    def test_get_specific_schedules_from_storehouse_not_found(self):
821
        """Test get specific schedule ID that does not exist."""
822
        requested_id = "blah"
823
        api = self.get_app_test_client(self.napp)
824
        url = f'{self.server_name_url}/v2/evc/{requested_id}'
825
826
        # Call URL
827
        response = api.get(url)
828
829
        expected = {'response': 'circuit_id blah not found'}
830
        # Assert response not found
831
        self.assertEqual(response.status_code, 404, response.data)
832
        self.assertEqual(expected, json.loads(response.data))
833
834
    def _uni_from_dict_side_effect(self, uni_dict):
835
        interface_id = uni_dict.get("interface_id")
836
        tag_dict = uni_dict.get("tag")
837
        interface = Interface(interface_id, "0", "switch")
838
        return UNI(interface, tag_dict)
839
840
    @patch('apscheduler.schedulers.background.BackgroundScheduler.add_job')
841
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
842
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
843
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
844
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
845
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
846
    @patch('napps.kytos.mef_eline.models.EVC._validate')
847
    def test_create_schedule(self, *args):  # pylint: disable=too-many-locals
848
        """Test create a circuit schedule."""
849
        (validate_mock, evc_as_dict_mock, save_evc_mock,
850
         uni_from_dict_mock, sched_add_mock, storehouse_data_mock,
851
         scheduler_add_job_mock) = args
852
853
        validate_mock.return_value = True
854
        save_evc_mock.return_value = True
855
        uni_from_dict_mock.side_effect = self._uni_from_dict_side_effect
856
        evc_as_dict_mock.return_value = {}
857
        sched_add_mock.return_value = True
858
        storehouse_data_mock.return_value = {}
859
860
        self._add_storehouse_schedule_data(storehouse_data_mock)
861
862
        requested_id = "bb:bb:bb"
863
        api = self.get_app_test_client(self.napp)
864
        url = f'{self.server_name_url}/v2/evc/schedule/'
865
866
        payload = {
867
              "circuit_id": requested_id,
868
              "schedule": {
869
                "frequency": "1 * * * *",
870
                "action": "create"
871
              }
872
            }
873
874
        # Call URL
875
        response = api.post(url, data=json.dumps(payload),
876
                            content_type='application/json')
877
878
        response_json = json.loads(response.data)
879
880
        self.assertEqual(response.status_code, 201, response.data)
881
        scheduler_add_job_mock.assert_called_once()
882
        save_evc_mock.assert_called_once()
883
        self.assertEqual(payload["schedule"]["frequency"],
884
                         response_json["frequency"])
885
        self.assertEqual(payload["schedule"]["action"],
886
                         response_json["action"])
887
        self.assertIsNotNone(response_json["id"])
888
889
    @patch('apscheduler.schedulers.background.BackgroundScheduler.remove_job')
890
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
891
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
892
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
893
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
894
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
895
    @patch('napps.kytos.mef_eline.models.EVC._validate')
896
    def test_update_schedule(self, *args):  # pylint: disable=too-many-locals
897
        """Test create a circuit schedule."""
898
        (validate_mock, evc_as_dict_mock, save_evc_mock,
899
         uni_from_dict_mock, sched_add_mock, storehouse_data_mock,
900
         scheduler_remove_job_mock) = args
901
902
        storehouse_payload_1 = {
903
            "aa:aa:aa": {
904
                "id": "aa:aa:aa",
905
                "name": "my evc1",
906
                "uni_a": {
907
                    "interface_id": "00:00:00:00:00:00:00:01:1",
908
                    "tag": {
909
                        "tag_type": 1,
910
                        "value": 80
911
                    }
912
                },
913
                "uni_z": {
914
                    "interface_id": "00:00:00:00:00:00:00:02:2",
915
                    "tag": {
916
                        "tag_type": 1,
917
                        "value": 1
918
                    }
919
                },
920
                "circuit_scheduler": [{
921
                    "id": "1",
922
                    "frequency": "* * * * *",
923
                    "action": "create"
924
                }
925
                ]
926
            }
927
        }
928
929
        validate_mock.return_value = True
930
        save_evc_mock.return_value = True
931
        sched_add_mock.return_value = True
932
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
933
        evc_as_dict_mock.return_value = {}
934
        storehouse_data_mock.return_value = storehouse_payload_1
935
        scheduler_remove_job_mock.return_value = True
936
937
        requested_schedule_id = "1"
938
        api = self.get_app_test_client(self.napp)
939
        url = f'{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}'
940
941
        payload = {
942
            "frequency": "*/1 * * * *",
943
            "action": "create"
944
        }
945
946
        # Call URL
947
        response = api.patch(url, data=json.dumps(payload),
948
                             content_type='application/json')
949
950
        response_json = json.loads(response.data)
951
952
        self.assertEqual(response.status_code, 200, response.data)
953
        scheduler_remove_job_mock.assert_called_once()
954
        save_evc_mock.assert_called_once()
955
        self.assertEqual(payload["frequency"], response_json["frequency"])
956
        self.assertEqual(payload["action"], response_json["action"])
957
        self.assertIsNotNone(response_json["id"])
958
959
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
960
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
961
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
962
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
963
    @patch('napps.kytos.mef_eline.models.EVC._validate')
964
    def test_update_schedule_archived(self, *args):
965
        """Test create a circuit schedule."""
966
        # pylint: disable=too-many-locals
967
        (validate_mock, evc_as_dict_mock,
968
         uni_from_dict_mock, sched_add_mock, storehouse_data_mock) = args
969
970
        storehouse_payload_1 = {
971
            "aa:aa:aa": {
972
                "id": "aa:aa:aa",
973
                "name": "my evc1",
974
                "archived": True,
975
                "circuit_scheduler": [{
976
                    "id": "1",
977
                    "frequency": "* * * * *",
978
                    "action": "create"
979
                }
980
                ]
981
            }
982
        }
983
984
        validate_mock.return_value = True
985
        sched_add_mock.return_value = True
986
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
987
        evc_as_dict_mock.return_value = {}
988
        storehouse_data_mock.return_value = storehouse_payload_1
989
990
        requested_schedule_id = "1"
991
        api = self.get_app_test_client(self.napp)
992
        url = f'{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}'
993
994
        payload = {
995
            "frequency": "*/1 * * * *",
996
            "action": "create"
997
        }
998
999
        # Call URL
1000
        response = api.patch(url, data=json.dumps(payload),
1001
                             content_type='application/json')
1002
1003
        self.assertEqual(response.status_code, 403, response.data)
1004
1005
    @patch('apscheduler.schedulers.background.BackgroundScheduler.remove_job')
1006
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
1007
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1008
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
1009
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1010
    @patch('napps.kytos.mef_eline.models.EVC._validate')
1011
    def test_delete_schedule(self, *args):
1012
        """Test create a circuit schedule."""
1013
        (validate_mock, evc_as_dict_mock, save_evc_mock,
1014
         uni_from_dict_mock, storehouse_data_mock,
1015
         scheduler_remove_job_mock) = args
1016
1017
        storehouse_payload_1 = {
1018
            "2": {
1019
                "id": "2",
1020
                "name": "my evc1",
1021
                "uni_a": {
1022
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1023
                    "tag": {
1024
                        "tag_type": 1,
1025
                        "value": 80
1026
                    }
1027
                },
1028
                "uni_z": {
1029
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1030
                    "tag": {
1031
                        "tag_type": 1,
1032
                        "value": 1
1033
                    }
1034
                },
1035
                "circuit_scheduler": [{
1036
                    "id": "1",
1037
                    "frequency": "* * * * *",
1038
                    "action": "create"
1039
                }]
1040
            }
1041
        }
1042
        validate_mock.return_value = True
1043
        save_evc_mock.return_value = True
1044
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
1045
        evc_as_dict_mock.return_value = {}
1046
        storehouse_data_mock.return_value = storehouse_payload_1
1047
        scheduler_remove_job_mock.return_value = True
1048
1049
        requested_schedule_id = "1"
1050
        api = self.get_app_test_client(self.napp)
1051
        url = f'{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}'
1052
1053
        # Call URL
1054
        response = api.delete(url)
1055
1056
        self.assertEqual(response.status_code, 200, response.data)
1057
        scheduler_remove_job_mock.assert_called_once()
1058
        save_evc_mock.assert_called_once()
1059
        self.assertIn("Schedule removed", f"{response.data}")
1060
1061
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
1062
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1063
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1064
    @patch('napps.kytos.mef_eline.models.EVC._validate')
1065
    def test_delete_schedule_archived(self, *args):
1066
        """Test create a circuit schedule."""
1067
        (validate_mock, evc_as_dict_mock,
1068
         uni_from_dict_mock, storehouse_data_mock) = args
1069
1070
        storehouse_payload_1 = {
1071
            "2": {
1072
                "id": "2",
1073
                "name": "my evc1",
1074
                "archived": True,
1075
                "circuit_scheduler": [{
1076
                    "id": "1",
1077
                    "frequency": "* * * * *",
1078
                    "action": "create"
1079
                }]
1080
            }
1081
        }
1082
1083
        validate_mock.return_value = True
1084
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
1085
        evc_as_dict_mock.return_value = {}
1086
        storehouse_data_mock.return_value = storehouse_payload_1
1087
1088
        requested_schedule_id = "1"
1089
        api = self.get_app_test_client(self.napp)
1090
        url = f'{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}'
1091
1092
        # Call URL
1093
        response = api.delete(url)
1094
1095
        self.assertEqual(response.status_code, 403, response.data)
1096
1097
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1098
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
1099
    @patch('napps.kytos.mef_eline.models.EVC._validate')
1100
    @patch('kytos.core.Controller.get_interface_by_id')
1101
    @patch('napps.kytos.mef_eline.models.EVCDeploy.deploy')
1102
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1103
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1104
    def test_update_circuit(self, *args):
1105
        """Test update a circuit circuit."""
1106
        (evc_as_dict_mock, uni_from_dict_mock, evc_deploy, *mocks) = args
1107
1108
        for mock in mocks:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable mocks does not seem to be defined.
Loading history...
1109
            mock.return_value = True
1110
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z', 'uni_a', 'uni_z']
1111
1112
        api = self.get_app_test_client(self.napp)
1113
        payloads = [
1114
            {
1115
                "name": "my evc1",
1116
                "active": True,
1117
                "uni_a": {
1118
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1119
                    "tag": {
1120
                        "tag_type": 1,
1121
                        "value": 80
1122
                    }
1123
                },
1124
                "uni_z": {
1125
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1126
                    "tag": {
1127
                        "tag_type": 1,
1128
                        "value": 1
1129
                    }
1130
                }
1131
            },
1132
            {
1133
                "primary_path": [
1134
                    {
1135
                        "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1136
                        "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"}
1137
                    }
1138
                ]
1139
            },
1140
            {
1141
                "priority": 3
1142
            },
1143
            {
1144
                "enable": True
1145
            }
1146
        ]
1147
1148
        evc_as_dict_mock.return_value = payloads[0]
1149
        response = api.post(f'{self.server_name_url}/v2/evc/',
1150
                            data=json.dumps(payloads[0]),
1151
                            content_type='application/json')
1152
        self.assertEqual(201, response.status_code)
1153
1154
        evc_deploy.reset_mock()
1155
        evc_as_dict_mock.return_value = payloads[1]
1156
        current_data = json.loads(response.data)
1157
        circuit_id = current_data['circuit_id']
1158
        response = api.patch(f'{self.server_name_url}/v2/evc/{circuit_id}',
1159
                             data=json.dumps(payloads[1]),
1160
                             content_type='application/json')
1161
        evc_deploy.assert_called_once()
1162
        self.assertEqual(200, response.status_code)
1163
1164
        evc_deploy.reset_mock()
1165
        evc_as_dict_mock.return_value = payloads[2]
1166
        response = api.patch(f'{self.server_name_url}/v2/evc/{circuit_id}',
1167
                             data=json.dumps(payloads[2]),
1168
                             content_type='application/json')
1169
        evc_deploy.assert_not_called()
1170
        self.assertEqual(200, response.status_code)
1171
1172
        evc_deploy.reset_mock()
1173
        response = api.patch(f'{self.server_name_url}/v2/evc/{circuit_id}',
1174
                             data='{"priority":5,}',
1175
                             content_type='application/json')
1176
        evc_deploy.assert_not_called()
1177
        self.assertEqual(400, response.status_code)
1178
1179
        evc_deploy.reset_mock()
1180
        response = api.patch(f'{self.server_name_url}/v2/evc/{circuit_id}',
1181
                             data=json.dumps(payloads[3]),
1182
                             content_type='application/json')
1183
        evc_deploy.assert_called_once()
1184
        self.assertEqual(200, response.status_code)
1185
1186
        response = api.patch(f'{self.server_name_url}/v2/evc/1234',
1187
                             data=json.dumps(payloads[1]),
1188
                             content_type='application/json')
1189
        current_data = json.loads(response.data)
1190
        expected_data = f'circuit_id 1234 not found'
1191
        self.assertEqual(current_data['response'], expected_data)
1192
        self.assertEqual(404, response.status_code)
1193
1194
        api.delete(f'{self.server_name_url}/v2/evc/{circuit_id}')
1195
        evc_deploy.reset_mock()
1196
        response = api.patch(f'{self.server_name_url}/v2/evc/{circuit_id}',
1197
                             data=json.dumps(payloads[1]),
1198
                             content_type='application/json')
1199
        evc_deploy.assert_not_called()
1200
        self.assertEqual(405, response.status_code)
1201
1202
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1203
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1204
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
1205
    @patch('napps.kytos.mef_eline.models.EVC._validate')
1206
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1207
    def test_update_circuit_invalid_json(self, *args):
1208
        """Test update a circuit circuit."""
1209
        (evc_as_dict_mock, validate_mock, save_evc_mock,
1210
         uni_from_dict_mock, sched_add_mock) = args
1211
1212
        validate_mock.return_value = True
1213
        save_evc_mock.return_value = True
1214
        sched_add_mock.return_value = True
1215
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z', 'uni_a', 'uni_z']
1216
1217
        api = self.get_app_test_client(self.napp)
1218
        payload1 = {
1219
            "name": "my evc1",
1220
            "uni_a": {
1221
                "interface_id": "00:00:00:00:00:00:00:01:1",
1222
                "tag": {
1223
                    "tag_type": 1,
1224
                    "value": 80
1225
                }
1226
            },
1227
            "uni_z": {
1228
                "interface_id": "00:00:00:00:00:00:00:02:2",
1229
                "tag": {
1230
                    "tag_type": 1,
1231
                    "value": 1
1232
                }
1233
            }
1234
        }
1235
1236
        payload2 = {
1237
            "dynamic_backup_path": True,
1238
        }
1239
1240
        evc_as_dict_mock.return_value = payload1
1241
        response = api.post(f'{self.server_name_url}/v2/evc/',
1242
                            data=json.dumps(payload1),
1243
                            content_type='application/json')
1244
        self.assertEqual(201, response.status_code)
1245
1246
        evc_as_dict_mock.return_value = payload2
1247
        current_data = json.loads(response.data)
1248
        circuit_id = current_data['circuit_id']
1249
        response = api.patch(f'{self.server_name_url}/v2/evc/{circuit_id}',
1250
                             data=payload2,
1251
                             content_type='application/json')
1252
        current_data = json.loads(response.data)
1253
        expected_data = f'Bad Request: The request is not a valid JSON.'
1254
        self.assertEqual(current_data['response'], expected_data)
1255
        self.assertEqual(400, response.status_code)
1256
1257
    def test_handle_link_up(self):
1258
        """Test handle_link_up method."""
1259
        evc_mock = create_autospec(EVC)
1260
        evc_mock.is_enabled = MagicMock(side_effect=[True, False, True])
1261
        type(evc_mock).archived = \
1262
            PropertyMock(side_effect=[True, False, False])
1263
        evcs = [evc_mock, evc_mock, evc_mock]
1264
        event = KytosEvent(name='test', content={'link': 'abc'})
1265
        self.napp.circuits = dict(zip(['1', '2', '3'], evcs))
1266
        self.napp.handle_link_up(event)
1267
        evc_mock.handle_link_up.assert_called_once_with('abc')
1268
1269
    def test_handle_link_down(self):
1270
        """Test handle_link_down method."""
1271
        evc_mock = create_autospec(EVC)
1272
        evc_mock.is_affected_by_link = \
1273
            MagicMock(side_effect=[True, False, True])
1274
        evcs = [evc_mock, evc_mock, evc_mock]
1275
        event = KytosEvent(name='test', content={'link': 'abc'})
1276
        self.napp.circuits = dict(zip(['1', '2', '3'], evcs))
1277
        self.napp.handle_link_down(event)
1278
        evc_mock.handle_link_down.assert_has_calls([call(), call()])
1279