Test Failed
Pull Request — master (#140)
by Rogerio
04:22
created

TestMain.test_circuit_with_valid_id()   A

Complexity

Conditions 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 12
Ratio 100 %

Importance

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