Test Failed
Push — master ( e254e3...e50c4e )
by Antonio
03:12 queued 11s
created

build.tests.test_main   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 1201
Duplicated Lines 4.16 %

Importance

Changes 0
Metric Value
eloc 867
dl 50
loc 1201
rs 9.173
c 0
b 0
f 0
wmc 37

33 Methods

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

How to fix   Duplicated Code   

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:

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