Dashboard with Network and Platform NFVi metrics
[yardstick.git] / yardstick / tests / unit / network_services / vnf_generic / vnf / test_tg_landslide.py
1 # Copyright (c) 2018 Intel Corporation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import copy
16 import mock
17 import requests
18 import time
19 import unittest
20 import uuid
21
22 from yardstick.benchmark.contexts import base as ctx_base
23 from yardstick.common import exceptions
24 from yardstick.common import utils as common_utils
25 from yardstick.common import yaml_loader
26 from yardstick.network_services import utils as net_serv_utils
27 from yardstick.network_services.traffic_profile import landslide_profile
28 from yardstick.network_services.vnf_generic.vnf import sample_vnf
29 from yardstick.network_services.vnf_generic.vnf import tg_landslide
30
31
32 NAME = "tg__0"
33
34 EXAMPLE_URL = 'http://example.com/'
35 TCL_SUCCESS_RESPONSE = 'ls_ok'
36
37 TEST_SERVERS = [
38     {'ip': '192.168.122.101',
39      'phySubnets': [
40          {'mask': '/24',
41           'base': '10.42.32.100',
42           'numIps': 20,
43           'name': 'eth1'}
44      ],
45      'role': 'SGW_Node',
46      'name': 'TestServer_1'},
47     {'ip': '192.168.122.102',
48      'phySubnets': [
49          {'mask': '/24',
50           'base': '10.42.32.1',
51           'numIps': 100,
52           'name': 'eth1'
53           },
54          {'mask': '/24',
55           'base': '10.42.33.1',
56           'numIps': 100,
57           'name': 'eth2'}
58      ],
59      'preResolvedArpAddress': [
60          {'NumNodes': 1,
61           'StartingAddress': '10.42.33.5'}
62      ],
63      'role': 'SGW_Nodal',
64      'name': 'TestServer_2',
65      'thread_model': 'Fireball'
66      }
67 ]
68
69 TS1_SUTS = [
70     {'name': 'SGW - C TestNode',
71      'role': 'SgwControlAddr',
72      'managementIp': '12.0.1.1',
73      'ip': '10.42.32.100',
74      'phy': 'eth5',
75      'nextHop': '10.42.32.5'
76      },
77     {'name': 'SGW - U TestNode',
78      'role': 'SgwUserAddr',
79      'managementIp': '12.0.1.2',
80      'ip': '10.42.32.101',
81      'phy': 'eth5',
82      'nextHop': '10.42.32.5'
83      }
84 ]
85
86 TS2_SUTS = [
87     {'name': 'eNodeB TestNode',
88      'role': 'EnbUserAddr',
89      'managementIp': '12.0.2.1',
90      'ip': '10.42.32.2',
91      'phy': 'eth5',
92      'nextHop': '10.42.32.5'
93      },
94     {'name': 'MME TestNode',
95      'role': 'MmeControlAddr',
96      'managementIp': '12.0.3.1',
97      'ip': '10.42.32.1',
98      'phy': 'eth5',
99      'nextHop': '10.42.32.5'
100      },
101     {'name': 'NetHost TestNode',
102      'role': 'NetworkHostAddrLocal',
103      'managementIp': '12.0.4.1',
104      'ip': '10.42.33.1',
105      'phy': 'eth5',
106      'nextHop': '10.42.32.5'
107      },
108     {'name': 'PGW TestNode',
109      'role': 'PgwV4Sut',
110      'managementIp': '12.0.5.1',
111      'ip': '10.42.32.105',
112      'phy': 'eth5',
113      'nextHop': '10.42.32.5'
114      },
115     {'name': 'SGW - C SUT',
116      'role': 'SgwSut',
117      'managementIp': '12.0.6.1',
118      'ip': '10.42.32.100'
119      },
120     {'name': 'SGW - U SUT',
121      'role': 'SgwUserSut',
122      'managementIp': '12.0.6.2',
123      'ip': '10.42.32.101'}
124 ]
125
126 VNFD = {
127     'vnfd:vnfd-catalog': {
128         'vnfd': [{
129             'short-name': 'landslide',
130             'vdu': [{
131                 'description': 'AB client interface details',
132                 'name': 'abclient-baremetal',
133                 'id': 'abclient-baremetal',
134                 'external-interface': []}],
135             'description': 'Spirent Landslide traffic generator',
136             'config': [{'test_server': TEST_SERVERS[0], 'suts': TS1_SUTS},
137                        {'test_server': TEST_SERVERS[1], 'suts': TS2_SUTS}],
138             'mgmt-interface': {
139                 'vdu-id': 'landslide-tas',
140                 'user': 'user',
141                 'password': 'user',
142                 'super-user': 'super-user',
143                 'super-user-password': 'super-user-password',
144                 'cfguser_password': 'cfguser_password',
145                 'license': 48,
146                 'proto': 'http',
147                 'ip': '1.1.1.1'},
148             'benchmark': {
149                 'kpi': [
150                     'tx_throughput_mbps',
151                     'rx_throughput_mbps',
152                     'in_packets',
153                     'out_packets',
154                     'activation_rate_sessps',
155                     'deactivation_rate_sessps']},
156             'id': 'LandslideTrafficGen',
157             'name': 'LandslideTrafficGen'}]}}
158
159 TAS_INFO = VNFD['vnfd:vnfd-catalog']['vnfd'][0]['mgmt-interface']
160
161 DMF_CFG = {
162     "dmf": {
163         "library": "test",
164         "name": "Basic UDP"
165     },
166     "clientPort": {
167         "clientPort": 2002,
168         "isClientPortRange": "false"
169     },
170     "dataProtocol": "udp",
171     "serverPort": 2003
172 }
173
174 RESERVATIONS = [
175     {'tsName': TEST_SERVERS[0]['name'],
176      'phySubnets': TEST_SERVERS[0]['phySubnets'],
177      'tsId': TEST_SERVERS[0]['name'],
178      'tsIndex': 0},
179     {'tsName': TEST_SERVERS[1]['name'],
180      'phySubnets': TEST_SERVERS[1]['phySubnets'],
181      'tsId': TEST_SERVERS[1]['name'],
182      'tsIndex': 1}]
183
184 SESSION_PROFILE = {
185     'keywords': '',
186     'duration': 60,
187     'iterations': 1,
188     'description': 'UE default bearer creation test case',
189     'name': 'default_bearer_capacity',
190     'reportOptions': {'format': 'CSV'},
191     'reservePorts': 'false',
192     'tsGroups': [
193         {
194             'testCases': [{
195                 'type': 'SGW_Node',
196                 'name': '',
197                 'linked': "false",
198                 'AssociatedPhys': '',
199                 'parameters': {
200                     'SgiPtpTunnelEn': 'false',
201                     'Gtp2Imsi': '505024101215074',
202                     'Sessions': '100000',
203                     'S5Protocol': 'GTPv2',
204                     'TrafficMtu': '1500',
205                     'Gtp2Version': '13.6.0',
206                     'BearerV4AddrPool': '1.0.0.1',
207                     'Gtp2Imei': '50502410121507',
208                     'PgwNodeEn': 'true',
209                     'DedicatedsPerDefaultBearer': '0',
210                     'DefaultBearers': '1',
211                     'SgwUserAddr': {
212                         'numLinksOrNodes': 1,
213                         'phy': 'eth1',
214                         'forcedEthInterface': '',
215                         'ip': 'SGW_USER_IP',
216                         'class': 'TestNode',
217                         'ethStatsEnabled': "false",
218                         'mtu': 1500
219                     },
220                     'SgwControlAddr': {
221                         'numLinksOrNodes': 1,
222                         'phy': 'eth1',
223                         'forcedEthInterface': '',
224                         'ip': 'SGW_CONTROL_IP',
225                         'class': 'TestNode',
226                         'ethStatsEnabled': "false",
227                         'mtu': 1500,
228                         'nextHop': 'SGW_CONTROL_NEXT_HOP'
229                     },
230                     'BearerAddrPool': '2001::1',
231                     'TestType': 'SGW-NODE'
232                 }
233             }],
234             'tsId': TEST_SERVERS[0]['name']},
235         {
236             'testCases': [{
237                 'type': 'SGW_Nodal',
238                 'name': '',
239                 'parameters': {
240                     'DataTraffic': 'Continuous',
241                     'TrafficStartType': 'When All Sessions Established',
242                     'NetworkHost': 'Local',
243                     'Gtp2Imsi': '505024101215074',
244                     'Dmf': {
245                         'mainflows': [
246                             {
247                                 'name': 'Basic UDP',
248                                 'library': 'test'
249                             }
250                         ],
251                         'class': 'Dmf',
252                         'instanceGroups': [
253                             {
254                                 'startPaused': "false",
255                                 'rate': 0,
256                                 'mainflowIdx': 0,
257                                 'mixType': ''
258                             }
259                         ]
260                     },
261                     'S5Protocol': 'GTPv2',
262                     'DataUserCfgFileEn': 'false',
263                     'PgwUserSutEn': 'false',
264                     'MmeControlAddr': {
265                         'numLinksOrNodes': 1,
266                         'phy': 'eth1',
267                         'forcedEthInterface': '',
268                         'ip': 'MME_CONTROL_IP',
269                         'class': 'TestNode',
270                         'ethStatsEnabled': "false",
271                         'mtu': 1500
272                     },
273                     'SgwUserSut': {
274                         'class': 'Sut',
275                         'name': 'SGW_USER_NAME'
276                     },
277                     'TestActivity': 'Capacity Test',
278                     'NetworkHostAddrLocal': {
279                         'numLinksOrNodes': 1,
280                         'phy': 'eth2',
281                         'forcedEthInterface': '',
282                         'ip': 'NET_HOST_IP',
283                         'class': 'TestNode',
284                         'ethStatsEnabled': "false",
285                         'mtu': 1500
286                     },
287                     'DedicatedsPerDefaultBearer': '0',
288                     'DisconnectRate': '1000.0',
289                     'Sessions': '100000',
290                     'SgwSut': {
291                         'class': 'Sut',
292                         'name': 'SGW_CONTROL_NAME'
293                     },
294                     'TrafficMtu': '1500',
295                     'Gtp2Version': '13.6.0',
296                     'Gtp2Imei': '50502410121507',
297                     'PgwNodeEn': 'false',
298                     'StartRate': '1000.0',
299                     'PgwV4Sut': {
300                         'class': 'Sut',
301                         'name': 'PGW_SUT_NAME'
302                     },
303                     'DefaultBearers': '1',
304                     'EnbUserAddr': {
305                         'numLinksOrNodes': 1,
306                         'phy': 'eth1',
307                         'forcedEthInterface': '',
308                         'ip': 'ENB_USER_IP',
309                         'class': 'TestNode',
310                         'ethStatsEnabled': "false",
311                         'mtu': 1500
312                     },
313                     'TestType': 'SGW-NODAL'
314                 }
315             }],
316             'tsId': TEST_SERVERS[1]['name']
317         }
318     ]
319 }
320
321
322 class TestLandslideTrafficGen(unittest.TestCase):
323     SCENARIO_CFG = {
324         'session_profile': '/traffic_profiles/landslide/'
325                            'landslide_session_default_bearer.yaml',
326         'task_path': '',
327         'runner': {
328             'type': 'Iteration',
329             'iterations': 1
330         },
331         'nodes': {
332             'tg__0': 'tg__0.traffic_gen',
333             'vnf__0': 'vnf__0.vnf_epc'
334         },
335         'topology': 'landslide_tg_topology.yaml',
336         'type': 'NSPerf',
337         'traffic_profile': '../../traffic_profiles/landslide/'
338                            'landslide_dmf_udp.yaml',
339         'options': {
340             'test_cases': [
341                 {
342                     'BearerAddrPool': '2002::2',
343                     'type': 'SGW_Node',
344                     'BearerV4AddrPool': '2.0.0.2',
345                     'Sessions': '90000'
346                 },
347                 {
348                     'StartRate': '900.0',
349                     'type': 'SGW_Nodal',
350                     'DisconnectRate': '900.0',
351                     'Sessions': '90000'
352                 }
353             ],
354             'dmf':
355                 {
356                     'transactionRate': 1000,
357                     'packetSize': 512
358                 }
359         }
360     }
361
362     CONTEXT_CFG = {
363         'contexts': [
364             {
365                 'type': 'Node',
366                 'name': 'traffic_gen',
367                 'file': '/etc/yardstick/nodes/pod_landslide.yaml'
368             },
369             {
370                 'type': 'Node',
371                 'name': 'vnf_epc',
372                 'file': '/etc/yardstick/nodes/pod_vepc_sut.yaml'
373             }
374         ]
375     }
376
377     TRAFFIC_PROFILE = {
378         "schema": "nsb:traffic_profile:0.1",
379         "name": "LandslideProfile",
380         "description": "Spirent Landslide traffic profile",
381         "traffic_profile": {
382             "traffic_type": "LandslideProfile"
383         },
384         "dmf_config": {
385             "dmf": {
386                 "library": "test",
387                 "name": "Basic UDP"
388             },
389             "description": "Basic data flow using UDP/IP",
390             "keywords": "UDP",
391             "dataProtocol": "udp"
392         }
393     }
394
395     SUCCESS_CREATED_CODE = 201
396     SUCCESS_OK_CODE = 200
397     SUCCESS_RECORD_ID = 5
398     TEST_USER_ID = 11
399
400     def setUp(self):
401         self._id = uuid.uuid1().int
402
403         self.mock_lsapi = mock.patch.object(tg_landslide, 'LsApi')
404         self.mock_lsapi.start()
405
406         self.mock_ssh_helper = mock.patch.object(sample_vnf, 'VnfSshHelper')
407         self.mock_ssh_helper.start()
408         self.vnfd = VNFD['vnfd:vnfd-catalog']['vnfd'][0]
409         self.ls_tg = tg_landslide.LandslideTrafficGen(
410             NAME, self.vnfd, self._id)
411         self.session_profile = copy.deepcopy(SESSION_PROFILE)
412         self.ls_tg.session_profile = self.session_profile
413
414         self.addCleanup(self._cleanup)
415
416     def _cleanup(self):
417         self.mock_lsapi.stop()
418         self.mock_ssh_helper.stop()
419
420     @mock.patch.object(net_serv_utils, 'get_nsb_option')
421     def test___init__(self, mock_get_nsb_option, *args):
422         _path_to_nsb = 'path/to/nsb'
423         mock_get_nsb_option.return_value = _path_to_nsb
424         ls_tg = tg_landslide.LandslideTrafficGen(NAME, self.vnfd, self._id)
425         self.assertIsInstance(ls_tg.resource_helper,
426                               tg_landslide.LandslideResourceHelper)
427         mock_get_nsb_option.assert_called_once_with('bin_path')
428         self.assertEqual(_path_to_nsb, ls_tg.bin_path)
429         self.assertEqual(NAME, ls_tg.name)
430         self.assertTrue(ls_tg.runs_traffic)
431         self.assertFalse(ls_tg.traffic_finished)
432         self.assertIsNone(ls_tg.session_profile)
433
434     def test_listen_traffic(self):
435         _traffic_profile = {}
436         self.assertIsNone(self.ls_tg.listen_traffic(_traffic_profile))
437
438     def test_terminate(self, *args):
439         self.ls_tg.resource_helper._tcl = mock.Mock()
440         self.assertIsNone(self.ls_tg.terminate())
441         self.ls_tg.resource_helper._tcl.disconnect.assert_called_once()
442
443     @mock.patch.object(ctx_base.Context, 'get_context_from_server',
444                        return_value='fake_context')
445     def test_instantiate(self, *args):
446         self.ls_tg._tg_process = mock.Mock()
447         self.ls_tg._tg_process.start = mock.Mock()
448         self.ls_tg.resource_helper.connect = mock.Mock()
449         self.ls_tg.resource_helper.create_test_servers = mock.Mock()
450         self.ls_tg.resource_helper.create_suts = mock.Mock()
451         self.ls_tg._load_session_profile = mock.Mock()
452         self.assertIsNone(self.ls_tg.instantiate(self.SCENARIO_CFG,
453                                                  self.CONTEXT_CFG))
454         self.ls_tg.resource_helper.connect.assert_called_once()
455         self.ls_tg.resource_helper.create_test_servers.assert_called_once()
456         _suts_blocks_num = len([item['suts'] for item in self.vnfd['config']])
457         self.assertEqual(_suts_blocks_num,
458                          self.ls_tg.resource_helper.create_suts.call_count)
459         self.ls_tg._load_session_profile.assert_called_once()
460
461     @mock.patch.object(tg_landslide.LandslideResourceHelper,
462                        'get_running_tests')
463     def test_run_traffic(self, mock_get_tests, *args):
464         self.ls_tg.resource_helper._url = EXAMPLE_URL
465         self.ls_tg.scenario_helper.scenario_cfg = self.SCENARIO_CFG
466         mock_traffic_profile = mock.Mock(
467             spec=landslide_profile.LandslideProfile)
468         mock_traffic_profile.dmf_config = {'keywords': 'UDP',
469                                            'dataProtocol': 'udp'}
470         mock_traffic_profile.params = self.TRAFFIC_PROFILE
471         self.ls_tg.resource_helper._user_id = self.TEST_USER_ID
472         mock_get_tests.return_value = [{'id': self.SUCCESS_RECORD_ID,
473                                         'testStateOrStep': 'COMPLETE'}]
474         mock_post = mock.Mock()
475         mock_post.status_code = self.SUCCESS_CREATED_CODE
476         mock_post.json.return_value = {'id': self.SUCCESS_RECORD_ID}
477         mock_session = mock.Mock(spec=requests.Session)
478         mock_session.post.return_value = mock_post
479         self.ls_tg.resource_helper.session = mock_session
480         self.ls_tg.resource_helper._tcl = mock.Mock()
481         _tcl = self.ls_tg.resource_helper._tcl
482         self.assertIsNone(self.ls_tg.run_traffic(mock_traffic_profile))
483         self.assertEqual(self.SUCCESS_RECORD_ID,
484                          self.ls_tg.resource_helper.run_id)
485         mock_traffic_profile.update_dmf.assert_called_with(
486             self.ls_tg.scenario_helper.all_options)
487         _tcl.create_dmf.assert_called_with(mock_traffic_profile.dmf_config)
488         _tcl.create_test_session.assert_called_with(self.session_profile)
489
490     @mock.patch.object(tg_landslide.LandslideResourceHelper,
491                        'check_running_test_state')
492     def test_collect_kpi(self, mock_check_running_test_state, *args):
493         self.ls_tg.resource_helper.run_id = self.SUCCESS_RECORD_ID
494         mock_check_running_test_state.return_value = 'COMPLETE'
495         self.assertEqual({'done': True}, self.ls_tg.collect_kpi())
496         mock_check_running_test_state.assert_called_once()
497
498     def test_wait_for_instantiate(self):
499         self.assertIsNone(self.ls_tg.wait_for_instantiate())
500         self.ls_tg.wait_for_instantiate()
501
502     def test__update_session_suts_no_tc_role(self, *args):
503         _suts = [{'role': 'epc_role'}]
504         _testcase = {'parameters': {'diff_epc_role': {'class': 'Sut'}}}
505         res = self.ls_tg._update_session_suts(_suts, _testcase)
506         self.assertEqual(_testcase, res)
507
508     def test__update_session_suts(self, *args):
509
510         def get_testnode_param(role, key, session_prof):
511             """ Get value by key from the deep nested dict to avoid calls like:
512             e.g. session_prof['tsGroups'][0]['testCases'][1]['parameters'][key]
513             """
514             for group in session_prof['tsGroups']:
515                 for tc in group['testCases']:
516                     tc_params = tc['parameters']
517                     if tc_params.get(role):
518                         return tc_params[role][key]
519
520         def get_sut_param(role, key, suts):
521             """ Search list of dicts for one with specific role.
522             Return the value of related dict by key. Expect key presence.
523             """
524             for sut in suts:
525                 if sut.get('role') == role:
526                     return sut[key]
527
528         # TestNode to verify
529         testnode_role = 'SgwControlAddr'
530         # SUT to verify
531         sut_role = 'SgwUserSut'
532
533         config_suts = [config['suts'] for config in self.vnfd['config']]
534         session_tcs = [_tc for _ts_group in self.ls_tg.session_profile['tsGroups']
535                        for _tc in _ts_group['testCases']]
536         for suts, tc in zip(config_suts, session_tcs):
537             self.assertEqual(tc, self.ls_tg._update_session_suts(suts, tc))
538
539         # Verify TestNode class objects keys were updated
540         for _key in {'ip', 'phy', 'nextHop'}:
541             self.assertEqual(
542                 get_testnode_param(testnode_role, _key, self.ls_tg.session_profile),
543                 get_sut_param(testnode_role, _key, TS1_SUTS))
544         # Verify Sut class objects name was updated
545         self.assertEqual(
546             get_testnode_param(sut_role, 'name', self.ls_tg.session_profile),
547             get_sut_param(sut_role, 'name', TS2_SUTS))
548
549     def test__update_session_test_servers(self, *args):
550         for ts_index, ts in enumerate(TEST_SERVERS):
551             self.assertIsNone(
552                 self.ls_tg._update_session_test_servers(ts, ts_index))
553         # Verify preResolvedArpAddress key was added
554         self.assertTrue(any(
555             _item.get('preResolvedArpAddress')
556             for _item in self.ls_tg.session_profile['tsGroups']))
557         # Verify reservations key was added to session profile
558         self.assertEqual(RESERVATIONS,
559                          self.ls_tg.session_profile.get('reservations'))
560         self.assertEqual('true',
561                          self.ls_tg.session_profile.get('reservePorts'))
562
563     def test__update_session_tc_params_assoc_phys(self):
564         _tc_options = {'AssociatedPhys': 'eth1'}
565         _testcase = {}
566         _testcase_orig = copy.deepcopy(_testcase)
567         res = self.ls_tg._update_session_tc_params(_tc_options, _testcase)
568         self.assertNotEqual(_testcase_orig, res)
569         self.assertEqual(_tc_options, _testcase)
570
571     def test__update_session_tc_params(self, *args):
572
573         def get_session_tc_param_value(param, tc_type, session_prof):
574             """ Get param value from the deep nested dict to avoid calls like:
575             session_prof['tsGroups'][0]['testCases'][0]['parameters'][key]
576             """
577             for test_group in session_prof['tsGroups']:
578                 session_tc = test_group['testCases'][0]
579                 if session_tc['type'] == tc_type:
580                     return session_tc['parameters'].get(param)
581
582         session_tcs = [_tc for _ts_group in self.ls_tg.session_profile['tsGroups']
583                        for _tc in _ts_group['testCases']]
584         scenario_tcs = [_tc for _tc in
585                         self.SCENARIO_CFG['options']['test_cases']]
586         for tc_options, tc in zip(scenario_tcs, session_tcs):
587             self.assertEqual(
588                 tc,
589                 self.ls_tg._update_session_tc_params(tc_options, tc))
590
591         # Verify that each test case parameter was updated
592         # Params been compared are deeply nested. Using loops to ease access.
593         for _tc in self.SCENARIO_CFG['options']['test_cases']:
594             for _key, _val in _tc.items():
595                 if _key != 'type':
596                     self.assertEqual(
597                         _val,
598                         get_session_tc_param_value(_key, _tc.get('type'),
599                                                    self.ls_tg.session_profile))
600
601     @mock.patch.object(common_utils, 'open_relative_file')
602     @mock.patch.object(yaml_loader, 'yaml_load')
603     @mock.patch.object(tg_landslide.LandslideTrafficGen,
604                        '_update_session_test_servers')
605     @mock.patch.object(tg_landslide.LandslideTrafficGen,
606                        '_update_session_suts')
607     @mock.patch.object(tg_landslide.LandslideTrafficGen,
608                        '_update_session_tc_params')
609     def test__load_session_profile(self, mock_upd_ses_tc_params,
610                                    mock_upd_ses_suts, mock_upd_ses_ts,
611                                    mock_yaml_load, *args):
612         self.ls_tg.scenario_helper.scenario_cfg = \
613             copy.deepcopy(self.SCENARIO_CFG)
614         mock_yaml_load.return_value = copy.deepcopy(SESSION_PROFILE)
615         self.assertIsNone(self.ls_tg._load_session_profile())
616         self.assertIsNotNone(self.ls_tg.session_profile)
617         # Number of blocks in configuration files
618         # Number of test servers, suts and tc params blocks should be equal
619         _config_files_blocks_num = len([item['test_server']
620                                         for item in self.vnfd['config']])
621         self.assertEqual(_config_files_blocks_num,
622                          mock_upd_ses_ts.call_count)
623         self.assertEqual(_config_files_blocks_num,
624                          mock_upd_ses_suts.call_count)
625         self.assertEqual(_config_files_blocks_num,
626                          mock_upd_ses_tc_params.call_count)
627
628     @mock.patch.object(common_utils, 'open_relative_file')
629     @mock.patch.object(yaml_loader, 'yaml_load')
630     def test__load_session_profile_unequal_num_of_cfg_blocks(
631             self, mock_yaml_load, *args):
632         vnfd = copy.deepcopy(VNFD['vnfd:vnfd-catalog']['vnfd'][0])
633         ls_traffic_gen = tg_landslide.LandslideTrafficGen(NAME, vnfd, self._id)
634         ls_traffic_gen.scenario_helper.scenario_cfg = self.SCENARIO_CFG
635         mock_yaml_load.return_value = copy.deepcopy(SESSION_PROFILE)
636         # Delete test_servers item from pod file to make it not valid
637         ls_traffic_gen.vnfd_helper['config'].pop()
638         with self.assertRaises(RuntimeError):
639             ls_traffic_gen._load_session_profile()
640
641     @mock.patch.object(common_utils, 'open_relative_file')
642     @mock.patch.object(yaml_loader, 'yaml_load')
643     def test__load_session_profile_test_type_mismatch(self, mock_yaml_load,
644                                                       *args):
645         vnfd = copy.deepcopy(VNFD['vnfd:vnfd-catalog']['vnfd'][0])
646         # Swap test servers data in pod file
647         vnfd['config'] = list(reversed(vnfd['config']))
648         ls_tg = tg_landslide.LandslideTrafficGen(NAME, vnfd, self._id)
649         ls_tg.scenario_helper.scenario_cfg = self.SCENARIO_CFG
650         mock_yaml_load.return_value = SESSION_PROFILE
651         with self.assertRaises(RuntimeError):
652             ls_tg._load_session_profile()
653
654
655 class TestLandslideResourceHelper(unittest.TestCase):
656
657     PROTO_PORT = 8080
658     EXAMPLE_URL = ''.join([TAS_INFO['proto'], '://', TAS_INFO['ip'], ':',
659                            str(PROTO_PORT), '/api/'])
660     SUCCESS_CREATED_CODE = 201
661     SUCCESS_OK_CODE = 200
662     INVALID_REST_CODE = '400'
663     NOT_MODIFIED_CODE = 500810
664     ERROR_CODE = 500800
665     SUCCESS_RECORD_ID = 11
666     EXPIRE_DATE = '2020/01/01 12:00 FLE Standard Time'
667     TEST_USER = 'test'
668     TEST_TERMINATED = 1
669     AUTH_DATA = {'user': TAS_INFO['user'], 'password': TAS_INFO['password']}
670     TEST_SESSION_NAME = 'default_bearer_capacity'
671
672     USERS_DATA = {
673         "users": [{
674             "url": ''.join([EXAMPLE_URL, 'users/', str(SUCCESS_RECORD_ID)]),
675             "id": SUCCESS_RECORD_ID,
676             "level": 1,
677             "username": TEST_USER
678         }]
679     }
680
681     CREATE_USER_DATA = {'username': TAS_INFO['user'],
682                         'expiresOn': EXPIRE_DATE,
683                         'level': 1,
684                         'contactInformation': '',
685                         'fullName': 'Test User',
686                         'password': TAS_INFO['password'],
687                         'isActive': 'true'}
688
689     SUTS_DATA = {
690         "suts": [
691             {
692                 "url": ''.join([EXAMPLE_URL, 'suts/', str(SUCCESS_RECORD_ID)]),
693                 "id": SUCCESS_RECORD_ID,
694                 "name": "10.41.32.1"
695             }]}
696
697     TEST_SERVERS_DATA = {
698         "testServers": [
699             {
700                 "url": ''.join([EXAMPLE_URL, "testServers/1"]),
701                 "id": 1,
702                 "name": TEST_SERVERS[0]['name'],
703                 "state": "READY",
704                 "version": "16.4.0.10"
705             },
706             {
707                 "url": ''.join([EXAMPLE_URL, "testServers/2"]),
708                 "id": 2,
709                 "name": TEST_SERVERS[1]['name'],
710                 "state": "READY",
711                 "version": "16.4.0.10"
712             }
713
714         ]
715     }
716
717     RUN_ID = 3
718
719     RUNNING_TESTS_DATA = {
720         "runningTests": [{
721             "url": ''.join([EXAMPLE_URL, "runningTests/{}".format(RUN_ID)]),
722             "measurementsUrl": ''.join(
723                 [EXAMPLE_URL,
724                  "runningTests/{}/measurements".format(RUN_ID)]),
725             "criteriaUrl": ''.join(
726                 [EXAMPLE_URL,
727                  "runningTests/{}/criteria".format(RUN_ID)]),
728             "noteToUser": "",
729             "id": RUN_ID,
730             "library": SUCCESS_RECORD_ID,
731             "name": "default_bearer_capacity",
732             "user": TEST_USER,
733             "criteriaStatus": "NA",
734             "testStateOrStep": "COMPLETE"
735         }]}
736
737     TEST_RESULTS_DATA = {
738         "interval": 0,
739         "elapsedTime": 138,
740         "actualTime": 1521548057296,
741         "iteration": 1,
742         "tabs": {
743             "Test Summary": {
744                 "Start Time": "Tue Mar 20 07:11:55 CDT 2018",
745                 "Actual Dedicated Bearer Session Connects": "100",
746                 "Actual Dedicated Bearer Session Disconnects": "100",
747                 "Actual Disconnect Rate(Sessions / Second)(P - I)": "164.804",
748                 "Average Session Disconnect Time(P - I)": "5.024 s",
749                 "Total Data Sent + Received Packets / Sec(P - I)": "1,452.294"
750             }}}
751
752     def setUp(self):
753         self.mock_lsapi = mock.patch.object(tg_landslide, 'LsApi')
754         self.mock_lsapi.start()
755
756         mock_env_helper = mock.Mock()
757         self.res_helper = tg_landslide.LandslideResourceHelper(mock_env_helper)
758         self.res_helper._url = EXAMPLE_URL
759
760         self.addCleanup(self._cleanup)
761
762     def _cleanup(self):
763         self.mock_lsapi.stop()
764         self.res_helper._url = None
765
766     def test___init__(self, *args):
767         self.assertIsInstance(self.res_helper,
768                               tg_landslide.LandslideResourceHelper)
769         self.assertEqual({}, self.res_helper._result)
770         self.assertIsNone(self.res_helper.run_id)
771
772     @mock.patch.object(tg_landslide.LandslideResourceHelper,
773                        'stop_running_tests')
774     @mock.patch.object(tg_landslide.LandslideResourceHelper,
775                        'get_running_tests')
776     def test_abort_running_tests_no_running_tests(self, mock_get_tests,
777                                                   mock_stop_tests, *args):
778         tests_data = [{'id': self.SUCCESS_RECORD_ID,
779                        'testStateOrStep': 'COMPLETE'}]
780         mock_get_tests.return_value = tests_data
781         self.assertIsNone(self.res_helper.abort_running_tests())
782         mock_stop_tests.assert_not_called()
783
784     @mock.patch.object(time, 'sleep')
785     @mock.patch.object(tg_landslide.LandslideResourceHelper,
786                        'stop_running_tests')
787     @mock.patch.object(tg_landslide.LandslideResourceHelper,
788                        'get_running_tests')
789     def test_abort_running_tests(self, mock_get_tests, mock_stop_tests, *args):
790         test_states_seq = iter(['RUNNING', 'COMPLETE'])
791
792         def configure_mock(*args):
793             return [{'id': self.SUCCESS_RECORD_ID,
794                      'testStateOrStep': next(test_states_seq)}]
795
796         mock_get_tests.side_effect = configure_mock
797         self.assertIsNone(self.res_helper.abort_running_tests())
798         mock_stop_tests.assert_called_once_with(
799             running_test_id=self.SUCCESS_RECORD_ID,
800             force=True)
801         self.assertEqual(2, mock_get_tests.call_count)
802
803     @mock.patch.object(tg_landslide.LandslideResourceHelper,
804                        'stop_running_tests')
805     @mock.patch.object(tg_landslide.LandslideResourceHelper,
806                        'get_running_tests')
807     def test_abort_running_tests_error(self, mock_get_tests, mock_stop_tests,
808                                        *args):
809         tests_data = {'id': self.SUCCESS_RECORD_ID,
810                       'testStateOrStep': 'RUNNING'}
811         mock_get_tests.return_value = [tests_data]
812         with self.assertRaises(RuntimeError):
813             self.res_helper.abort_running_tests(timeout=1, delay=1)
814         mock_stop_tests.assert_called_with(
815             running_test_id=self.SUCCESS_RECORD_ID,
816             force=True)
817
818     def test__build_url(self, *args):
819         resource = 'users'
820         action = {'action': 'userCreate'}
821         expected_url = ''.join([EXAMPLE_URL, 'users?action=userCreate'])
822         self.assertEqual(expected_url,
823                          self.res_helper._build_url(resource, action))
824
825     def test__build_url_error(self, *args):
826         resource = ''
827         action = {'action': 'userCreate'}
828
829         with self.assertRaises(ValueError):
830             self.res_helper._build_url(resource, action)
831
832     def test_get_response_params(self, *args):
833         method = 'get'
834         resource = 'users'
835         mock_session = mock.Mock(spec=requests.Session)
836         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
837                          'json.return_value': self.USERS_DATA}
838         mock_session.get.return_value.configure_mock(**get_resp_data)
839         self.res_helper.session = mock_session
840         resp = self.res_helper.get_response_params(method, resource)
841         self.assertTrue(resp)
842
843     @mock.patch.object(tg_landslide.LandslideResourceHelper, '_get_users')
844     @mock.patch.object(time, 'time')
845     def test__create_user(self, mock_time, mock_get_users, *args):
846         mock_time.strftime.return_value = self.EXPIRE_DATE
847         post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE,
848                           'json.return_value': {'id': self.SUCCESS_RECORD_ID}}
849         mock_session = mock.Mock(spec=requests.Session)
850         mock_session.post.return_value.configure_mock(**post_resp_data)
851         self.res_helper.session = mock_session
852         self.assertEqual(self.SUCCESS_RECORD_ID,
853                          self.res_helper._create_user(self.AUTH_DATA))
854         mock_get_users.assert_not_called()
855
856     @mock.patch.object(tg_landslide.LandslideResourceHelper, '_modify_user')
857     @mock.patch.object(time, 'time')
858     def test__create_user_username_exists(self, mock_time, mock_modify_user,
859                                           *args):
860         mock_time.strftime.return_value = self.EXPIRE_DATE
861         mock_modify_user.return_value = {'id': self.SUCCESS_RECORD_ID,
862                                          'result': 'No changes requested'}
863         post_resp_data = {
864             'status_code': self.ERROR_CODE,
865             'json.return_value': {'id': self.SUCCESS_OK_CODE,
866                                   'apiCode': self.NOT_MODIFIED_CODE}}
867         mock_session = mock.Mock(spec=requests.Session)
868         mock_session.post.return_value.configure_mock(**post_resp_data)
869         self.res_helper.session = mock_session
870         res = self.res_helper._create_user(self.AUTH_DATA)
871         mock_modify_user.assert_called_once_with(TAS_INFO['user'],
872                                                  {'isActive': 'true'})
873         self.assertEqual(self.SUCCESS_RECORD_ID, res)
874
875     @mock.patch.object(time, 'time')
876     def test__create_user_error(self, mock_time, *args):
877         mock_time.strftime.return_value = self.EXPIRE_DATE
878         mock_session = mock.Mock(spec=requests.Session)
879         post_resp_data = {'status_code': self.SUCCESS_OK_CODE,
880                           'json.return_value': {'apiCode': self.ERROR_CODE}}
881         mock_session.post.return_value.configure_mock(**post_resp_data)
882         self.res_helper.session = mock_session
883         with self.assertRaises(exceptions.RestApiError):
884             self.res_helper._create_user(self.AUTH_DATA)
885
886     def test__modify_user(self, *args):
887         post_data = {'username': 'test_user'}
888         mock_session = mock.Mock(spec=requests.Session)
889         post_resp_data = {'status_code': self.SUCCESS_OK_CODE,
890                           'json.return_value': {'id': self.SUCCESS_RECORD_ID}}
891         mock_session.post.return_value.configure_mock(**post_resp_data)
892         self.res_helper.session = mock_session
893         res = self.res_helper._modify_user(username=self.TEST_USER,
894                                            fields=post_data)
895         self.assertEqual(self.SUCCESS_RECORD_ID, res['id'])
896
897     def test__modify_user_rest_resp_fail(self, *args):
898         post_data = {'non-existing-key': ''}
899         mock_session = mock.Mock(spec=requests.Session)
900         mock_session.post.ok = False
901         self.res_helper.session = mock_session
902         self.assertRaises(exceptions.RestApiError,
903                           self.res_helper._modify_user,
904                           username=self.TEST_USER, fields=post_data)
905         mock_session.post.assert_called_once()
906
907     def test__delete_user(self, *args):
908         mock_session = mock.Mock(spec=requests.Session)
909         self.res_helper.session = mock_session
910         self.assertIsNone(self.res_helper._delete_user(
911             username=self.TEST_USER))
912
913     def test__get_users(self, *args):
914         mock_session = mock.Mock(spec=requests.Session)
915         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
916                          'json.return_value': self.USERS_DATA}
917         mock_session.get.return_value.configure_mock(**get_resp_data)
918         self.res_helper.session = mock_session
919         self.assertEqual(self.USERS_DATA['users'],
920                          self.res_helper._get_users())
921
922     def test_exec_rest_request(self, *args):
923         resource = 'testServers'
924         action = {'action': 'modify'}
925         expected_url = ''.join([EXAMPLE_URL, 'testServers?action=modify'])
926         post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE,
927                           'json.return_value': {'id': self.SUCCESS_RECORD_ID}}
928         mock_session = mock.Mock(spec=requests.Session)
929         mock_session.post.return_value.configure_mock(**post_resp_data)
930         self.res_helper.session = mock_session
931         self.res_helper.exec_rest_request('post', resource, action)
932         self.res_helper.session.post.assert_called_once_with(expected_url,
933                                                              json={})
934
935     def test_exec_rest_request_unsupported_method_error(self, *args):
936         resource = 'testServers'
937         action = {'action': 'modify'}
938         with self.assertRaises(ValueError):
939             self.res_helper.exec_rest_request('patch', resource, action)
940
941     def test_exec_rest_request_missed_action_arg(self, *args):
942         resource = 'testServers'
943         with self.assertRaises(ValueError):
944             self.res_helper.exec_rest_request('post', resource)
945
946     def test_exec_rest_request_raise_exc(self):
947         resource = 'users'
948         action = {'action': 'modify'}
949         post_resp_data = {'status_code': self.ERROR_CODE,
950                           'json.return_value': {
951                               'status_code': self.ERROR_CODE}}
952         mock_session = mock.Mock(spec=requests.Session)
953         mock_session.post.return_value.configure_mock(**post_resp_data)
954         self.assertRaises(exceptions.RestApiError,
955                           self.res_helper.exec_rest_request,
956                           'post', resource, action, raise_exc=True)
957
958     @mock.patch.object(time, 'time')
959     def test_connect(self, mock_time, *args):
960         vnfd = VNFD['vnfd:vnfd-catalog']['vnfd'][0]
961         mock_time.strftime.return_value = self.EXPIRE_DATE
962         self.res_helper.vnfd_helper = vnfd
963
964         self.res_helper._tcl = mock.Mock()
965         post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE,
966                           'json.return_value': {'id': self.SUCCESS_RECORD_ID}}
967         mock_session = mock.Mock(spec=requests.Session, headers={})
968         mock_session.post.return_value.configure_mock(**post_resp_data)
969         self.res_helper.session = mock_session
970         self.assertIsInstance(self.res_helper.connect(), requests.Session)
971         self.res_helper._tcl.connect.assert_called_once_with(
972             TAS_INFO['ip'],
973             TAS_INFO['user'],
974             TAS_INFO['password'])
975
976     def test_disconnect(self, *args):
977         self.res_helper._tcl = mock.Mock()
978         self.assertIsNone(self.res_helper.disconnect())
979         self.assertIsNone(self.res_helper.session)
980         self.res_helper._tcl.disconnect.assert_called_once()
981
982     def test_terminate(self, *args):
983         self.assertIsNone(self.res_helper.terminate())
984         self.assertEqual(self.TEST_TERMINATED,
985                          self.res_helper._terminated.value)
986
987     def test_create_dmf(self, *args):
988         self.res_helper._tcl = mock.Mock()
989         self.assertIsNone(self.res_helper.create_dmf(DMF_CFG))
990         self.res_helper._tcl.create_dmf.assert_called_once_with(DMF_CFG)
991
992     def test_create_dmf_as_list(self, *args):
993         self.res_helper._tcl = mock.Mock()
994         self.assertIsNone(self.res_helper.create_dmf([DMF_CFG]))
995         self.res_helper._tcl.create_dmf.assert_called_once_with(DMF_CFG)
996
997     def test_delete_dmf(self, *args):
998         self.res_helper._tcl = mock.Mock()
999         self.assertIsNone(self.res_helper.delete_dmf(DMF_CFG))
1000         self.res_helper._tcl.delete_dmf.assert_called_once_with(DMF_CFG)
1001
1002     def test_delete_dmf_as_list(self, *args):
1003         self.res_helper._tcl = mock.Mock()
1004         self.assertIsNone(self.res_helper.delete_dmf([DMF_CFG]))
1005         self.res_helper._tcl.delete_dmf.assert_called_once_with(DMF_CFG)
1006
1007     @mock.patch.object(tg_landslide.LandslideResourceHelper, 'configure_sut')
1008     def test_create_suts(self, mock_configure_sut, *args):
1009         mock_session = mock.Mock(spec=requests.Session)
1010         post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE}
1011         mock_session.post.return_value.configure_mock(**post_resp_data)
1012         self.res_helper.session = mock_session
1013         self.assertIsNone(self.res_helper.create_suts(TS1_SUTS))
1014         mock_configure_sut.assert_not_called()
1015
1016     @mock.patch.object(tg_landslide.LandslideResourceHelper, 'configure_sut')
1017     def test_create_suts_sut_exists(self, mock_configure_sut, *args):
1018         sut_name = 'test_sut'
1019         suts = [
1020             {'name': sut_name,
1021              'role': 'SgwControlAddr',
1022              'managementIp': '12.0.1.1',
1023              'ip': '10.42.32.100'
1024              }
1025         ]
1026         mock_session = mock.Mock(spec=requests.Session)
1027         post_resp_data = {'status_code': self.NOT_MODIFIED_CODE}
1028         mock_session.post.return_value.configure_mock(**post_resp_data)
1029         self.res_helper.session = mock_session
1030         self.assertIsNone(self.res_helper.create_suts(suts))
1031         mock_configure_sut.assert_called_once_with(
1032             sut_name=sut_name,
1033             json_data={k: v for k, v in suts[0].items()
1034                        if k not in {'phy', 'nextHop', 'role', 'name'}})
1035
1036     def test_get_suts(self, *args):
1037         mock_session = mock.Mock(spec=requests.Session)
1038         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1039                          'json.return_value': self.SUTS_DATA}
1040         mock_session.get.return_value.configure_mock(**get_resp_data)
1041         self.res_helper.session = mock_session
1042         self.assertIsInstance(self.res_helper.get_suts(), list)
1043
1044     def test_get_suts_single_id(self, *args):
1045         mock_session = mock.Mock(spec=requests.Session)
1046         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1047                          'json.return_value': self.SUTS_DATA['suts'][0]}
1048         mock_session.get.return_value.configure_mock(**get_resp_data)
1049         self.res_helper.session = mock_session
1050         self.assertIsInstance(self.res_helper.get_suts(suts_id=2), dict)
1051
1052     def test_configure_sut(self, *args):
1053         post_data = {'managementIp': '2.2.2.2'}
1054         mock_session = mock.Mock(spec=requests.Session)
1055         post_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1056                           'json.return_value': {'id': self.SUCCESS_RECORD_ID}}
1057         mock_session.post.return_value.configure_mock(**post_resp_data)
1058         self.res_helper.session = mock_session
1059         self.assertIsNone(self.res_helper.configure_sut('test_name',
1060                                                         post_data))
1061         mock_session.post.assert_called_once()
1062
1063     def test_configure_sut_error(self, *args):
1064         post_data = {'managementIp': '2.2.2.2'}
1065         mock_session = mock.Mock(spec=requests.Session)
1066         post_resp_data = {'status_code': self.NOT_MODIFIED_CODE}
1067         mock_session.post.return_value.configure_mock(**post_resp_data)
1068         self.res_helper.session = mock_session
1069         with self.assertRaises(exceptions.RestApiError):
1070             self.res_helper.configure_sut('test_name', post_data)
1071
1072     def test_delete_suts(self, *args):
1073         mock_session = mock.Mock(spec=requests.Session)
1074         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1075                          'json.return_value': self.SUTS_DATA}
1076         delete_resp_data = {'status_code': self.SUCCESS_OK_CODE}
1077         mock_session.get.return_value.configure_mock(**get_resp_data)
1078         mock_session.delete.return_value.configure_mock(**delete_resp_data)
1079         self.res_helper.session = mock_session
1080         self.assertIsNone(self.res_helper.delete_suts())
1081         mock_session.delete.assert_called_once()
1082
1083     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1084                        'get_test_servers')
1085     def test__check_test_servers_state(self, mock_get_test_servers, *args):
1086         mock_get_test_servers.return_value = \
1087             self.TEST_SERVERS_DATA['testServers']
1088         self.res_helper._check_test_servers_state()
1089         mock_get_test_servers.assert_called_once()
1090
1091     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1092                        'get_test_servers')
1093     def test__check_test_servers_state_server_not_ready(
1094             self, mock_get_test_servers, *args):
1095         test_servers_not_ready = [
1096             {
1097                 "url": ''.join([EXAMPLE_URL, "testServers/1"]),
1098                 "id": 1,
1099                 "name": "TestServer_1",
1100                 "state": "NOT_READY",
1101                 "version": "16.4.0.10"
1102             }
1103         ]
1104
1105         mock_get_test_servers.return_value = test_servers_not_ready
1106         with self.assertRaises(RuntimeError):
1107             self.res_helper._check_test_servers_state(timeout=1, delay=0)
1108
1109     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1110                        '_check_test_servers_state')
1111     def test_create_test_servers(self, mock_check_ts_state, *args):
1112         test_servers_ids = [
1113             ts['id'] for ts in self.TEST_SERVERS_DATA['testServers']]
1114
1115         self.res_helper.license_data['lic_id'] = TAS_INFO['license']
1116         self.res_helper._tcl.create_test_server = mock.Mock()
1117         self.res_helper._tcl.create_test_server.side_effect = test_servers_ids
1118         self.assertIsNone(self.res_helper.create_test_servers(TEST_SERVERS))
1119         mock_check_ts_state.assert_called_once_with(test_servers_ids)
1120
1121     @mock.patch.object(tg_landslide.LandslideTclClient,
1122                        'resolve_test_server_name')
1123     @mock.patch.object(tg_landslide.LsTclHandler, 'execute')
1124     def test_create_test_servers_error(self, mock_execute,
1125                                        mock_resolve_ts_name, *args):
1126         self.res_helper.license_data['lic_id'] = TAS_INFO['license']
1127         # Return message for case test server wasn't created
1128         mock_execute.return_value = 'TS not found'
1129         # Return message for case test server name wasn't resolved
1130         mock_resolve_ts_name.return_value = 'TS not found'
1131         with self.assertRaises(RuntimeError):
1132             self.res_helper.create_test_servers(TEST_SERVERS)
1133
1134     def test_get_test_servers(self, *args):
1135         mock_session = mock.Mock(spec=requests.Session)
1136         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1137                          'json.return_value': self.TEST_SERVERS_DATA}
1138         mock_session.get.return_value.configure_mock(**get_resp_data)
1139         self.res_helper.session = mock_session
1140         res = self.res_helper.get_test_servers()
1141         self.assertEqual(self.TEST_SERVERS_DATA['testServers'], res)
1142
1143     def test_get_test_servers_by_id(self, *args):
1144         mock_session = mock.Mock(spec=requests.Session)
1145
1146         _ts = self.TEST_SERVERS_DATA['testServers'][0]
1147         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1148                          'json.return_value': _ts}
1149         mock_session.get.return_value.configure_mock(**get_resp_data)
1150         self.res_helper.session = mock_session
1151         res = self.res_helper.get_test_servers(test_server_ids=[_ts['id']])
1152         self.assertEqual([_ts], res)
1153
1154     def test_configure_test_servers(self, *args):
1155         mock_session = mock.Mock(spec=requests.Session)
1156         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1157                          'json.return_value': self.TEST_SERVERS_DATA}
1158         mock_session.get.return_value.configure_mock(**get_resp_data)
1159         self.res_helper.session = mock_session
1160         res = self.res_helper.configure_test_servers(
1161             action={'action': 'recycle'})
1162         self.assertEqual(
1163             [x['id'] for x in self.TEST_SERVERS_DATA['testServers']],
1164             res)
1165         self.assertEqual(len(self.TEST_SERVERS_DATA['testServers']),
1166                          mock_session.post.call_count)
1167
1168     def test_delete_test_servers(self, *args):
1169         mock_session = mock.Mock(spec=requests.Session)
1170         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1171                          'json.return_value': self.TEST_SERVERS_DATA}
1172         mock_session.get.return_value.configure_mock(**get_resp_data)
1173         self.res_helper.session = mock_session
1174         self.assertIsNone(self.res_helper.delete_test_servers())
1175         self.assertEqual(len(self.TEST_SERVERS_DATA['testServers']),
1176                          mock_session.delete.call_count)
1177
1178     def test_create_test_session_res_helper(self, *args):
1179         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1180         self.res_helper._tcl = mock.Mock()
1181         test_session = {'name': 'test'}
1182         self.assertIsNone(self.res_helper.create_test_session(test_session))
1183         self.res_helper._tcl.create_test_session.assert_called_once_with(
1184             {'name': 'test', 'library': self.SUCCESS_RECORD_ID})
1185
1186     @mock.patch.object(tg_landslide.LandslideTclClient,
1187                        'resolve_test_server_name',
1188                        return_value='Not Found')
1189     def test_create_test_session_ts_name_not_found(self, *args):
1190         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1191         test_session = {
1192             'duration': 60,
1193             'description': 'UE default bearer creation test case',
1194             'name': 'default_bearer_capacity',
1195             'tsGroups': [{'testCases': [{'type': 'SGW_Node',
1196                                          'name': ''}],
1197                           'tsId': 'TestServer_3'}]
1198         }
1199         with self.assertRaises(RuntimeError):
1200             self.res_helper.create_test_session(test_session)
1201
1202     def test_get_test_session(self, *args):
1203         test_session = {"name": self.TEST_SESSION_NAME}
1204         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1205         mock_session = mock.Mock(spec=requests.Session)
1206         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1207                          'json.return_value': test_session}
1208         mock_session.get.return_value.configure_mock(**get_resp_data)
1209         self.res_helper.session = mock_session
1210         res = self.res_helper.get_test_session(self.TEST_SESSION_NAME)
1211         self.assertEqual(test_session, res)
1212
1213     def test_configure_test_session(self, *args):
1214         test_session = {'name': self.TEST_SESSION_NAME}
1215         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1216         self.res_helper.user_lib_uri = 'libraries/{{}}/{}'.format(
1217             self.res_helper.test_session_uri)
1218         mock_session = mock.Mock(spec=requests.Session)
1219         self.res_helper.session = mock_session
1220         res = self.res_helper.configure_test_session(self.TEST_SESSION_NAME,
1221                                                      test_session)
1222         self.assertIsNotNone(res)
1223         mock_session.post.assert_called_once()
1224
1225     def test_delete_test_session(self, *args):
1226         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1227         self.res_helper.user_lib_uri = 'libraries/{{}}/{}'.format(
1228             self.res_helper.test_session_uri)
1229         mock_session = mock.Mock(spec=requests.Session)
1230         self.res_helper.session = mock_session
1231         res = self.res_helper.delete_test_session(self.TEST_SESSION_NAME)
1232         self.assertIsNotNone(res)
1233         mock_session.delete.assert_called_once()
1234
1235     def test_create_running_tests(self, *args):
1236         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1237         test_session = {'id': self.SUCCESS_RECORD_ID}
1238         mock_session = mock.Mock(spec=requests.Session)
1239         post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE,
1240                           'json.return_value': test_session}
1241         mock_session.post.return_value.configure_mock(**post_resp_data)
1242         self.res_helper.session = mock_session
1243         self.res_helper.create_running_tests(self.TEST_SESSION_NAME)
1244         self.assertEqual(self.SUCCESS_RECORD_ID, self.res_helper.run_id)
1245
1246     def test_create_running_tests_error(self, *args):
1247         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1248         mock_session = mock.Mock(spec=requests.Session)
1249         post_resp_data = {'status_code': self.NOT_MODIFIED_CODE}
1250         mock_session.post.return_value.configure_mock(**post_resp_data)
1251         self.res_helper.session = mock_session
1252         with self.assertRaises(exceptions.RestApiError):
1253             self.res_helper.create_running_tests(self.TEST_SESSION_NAME)
1254
1255     def test_get_running_tests(self, *args):
1256         mock_session = mock.Mock(spec=requests.Session)
1257         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1258                          'json.return_value': self.RUNNING_TESTS_DATA}
1259         mock_session.get.return_value.configure_mock(**get_resp_data)
1260         self.res_helper.session = mock_session
1261         res = self.res_helper.get_running_tests()
1262         self.assertEqual(self.RUNNING_TESTS_DATA['runningTests'], res)
1263
1264     def test_delete_running_tests(self, *args):
1265         mock_session = mock.Mock(spec=requests.Session)
1266         delete_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1267                             'json.return_value': self.RUNNING_TESTS_DATA}
1268         mock_session.delete.return_value.configure_mock(**delete_resp_data)
1269         self.res_helper.session = mock_session
1270         self.assertIsNone(self.res_helper.delete_running_tests())
1271
1272     def test__running_tests_action(self, *args):
1273         action = 'abort'
1274         mock_session = mock.Mock(spec=requests.Session)
1275         self.res_helper.session = mock_session
1276         res = self.res_helper._running_tests_action(self.SUCCESS_RECORD_ID,
1277                                                     action)
1278         self.assertIsNone(res)
1279
1280     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1281                        '_running_tests_action')
1282     def test_stop_running_tests(self, mock_tests_action, *args):
1283         res = self.res_helper.stop_running_tests(self.SUCCESS_RECORD_ID)
1284         self.assertIsNone(res)
1285         mock_tests_action.assert_called_once()
1286
1287     def test_check_running_test_state(self, *args):
1288         mock_session = mock.Mock(spec=requests.Session)
1289         get_resp_data = {
1290             'status_code': self.SUCCESS_OK_CODE,
1291             'json.return_value': self.RUNNING_TESTS_DATA["runningTests"][0]}
1292         mock_session.get.return_value.configure_mock(**get_resp_data)
1293         self.res_helper.session = mock_session
1294         res = self.res_helper.check_running_test_state(self.SUCCESS_RECORD_ID)
1295         self.assertEqual(
1296             self.RUNNING_TESTS_DATA["runningTests"][0]['testStateOrStep'],
1297             res)
1298
1299     def test_get_running_tests_results(self, *args):
1300         mock_session = mock.Mock(spec=requests.Session)
1301         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1302                          'json.return_value': self.TEST_RESULTS_DATA}
1303         mock_session.get.return_value.configure_mock(**get_resp_data)
1304         self.res_helper.session = mock_session
1305         res = self.res_helper.get_running_tests_results(
1306             self.SUCCESS_RECORD_ID)
1307         self.assertEqual(self.TEST_RESULTS_DATA, res)
1308
1309     def test__write_results(self, *args):
1310         res = self.res_helper._write_results(self.TEST_RESULTS_DATA)
1311         exp_res = {
1312             "Test Summary::Actual Dedicated Bearer Session Connects": 100.0,
1313             "Test Summary::Actual Dedicated Bearer Session Disconnects": 100.0,
1314             "Test Summary::Actual Disconnect Rate(Sessions / Second)(P - I)": 164.804,
1315             "Test Summary::Average Session Disconnect Time(P - I)": 5.024,
1316             "Test Summary::Total Data Sent + Received Packets / Sec(P - I)": 1452.294
1317         }
1318         self.assertEqual(exp_res, res)
1319
1320     def test__write_results_no_tabs(self, *args):
1321         _res_data = copy.deepcopy(self.TEST_RESULTS_DATA)
1322         del _res_data['tabs']
1323         # Return None if tabs not found in test results dict
1324         self.assertIsNone(self.res_helper._write_results(_res_data))
1325
1326     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1327                        'check_running_test_state')
1328     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1329                        'get_running_tests_results')
1330     def test_collect_kpi_test_running(self, mock_tests_results,
1331                                       mock_tests_state, *args):
1332         self.res_helper.run_id = self.SUCCESS_RECORD_ID
1333         mock_tests_state.return_value = 'RUNNING'
1334         mock_tests_results.return_value = self.TEST_RESULTS_DATA
1335         res = self.res_helper.collect_kpi()
1336         self.assertNotIn('done', res)
1337         mock_tests_state.assert_called_once_with(self.res_helper.run_id)
1338         mock_tests_results.assert_called_once_with(self.res_helper.run_id)
1339
1340     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1341                        'check_running_test_state')
1342     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1343                        'get_running_tests_results')
1344     def test_collect_kpi_test_completed(self, mock_tests_results,
1345                                         mock_tests_state, *args):
1346         self.res_helper.run_id = self.SUCCESS_RECORD_ID
1347         mock_tests_state.return_value = 'COMPLETE'
1348         res = self.res_helper.collect_kpi()
1349         self.assertIsNotNone(res)
1350         mock_tests_state.assert_called_once_with(self.res_helper.run_id)
1351         mock_tests_results.assert_not_called()
1352         self.assertDictContainsSubset({'done': True}, res)
1353
1354
1355 class TestLandslideTclClient(unittest.TestCase):
1356     def setUp(self):
1357         self.mock_tcl_handler = mock.Mock(spec=tg_landslide.LsTclHandler)
1358         self.ls_res_helper = mock.Mock(
1359             spec=tg_landslide.LandslideResourceHelper)
1360         self.ls_tcl_client = tg_landslide.LandslideTclClient(
1361             self.mock_tcl_handler,
1362             self.ls_res_helper)
1363
1364     def test___init__(self, *args):
1365         self.ls_tcl_client = tg_landslide.LandslideTclClient(
1366             self.mock_tcl_handler,
1367             self.ls_res_helper)
1368         self.assertIsNone(self.ls_tcl_client.tcl_server_ip)
1369         self.assertIsNone(self.ls_tcl_client._user)
1370         self.assertIsNone(self.ls_tcl_client._library_id)
1371         self.assertIsNone(self.ls_tcl_client._basic_library_id)
1372         self.assertEqual(set(), self.ls_tcl_client.ts_ids)
1373         self.assertIsInstance(self.ls_tcl_client._tc_types, set)
1374         self.assertIsNotNone(self.ls_tcl_client._tc_types)
1375
1376     def test_connect_login_success(self, *args):
1377         lib_id = '123'
1378         exec_responses = ['java0x2', lib_id, lib_id]
1379         auth = ('user', 'password')
1380         self.mock_tcl_handler.execute.side_effect = exec_responses
1381         self.ls_tcl_client.connect(TAS_INFO['ip'], *auth)
1382         self.assertEqual(lib_id, self.ls_tcl_client._library_id)
1383         self.assertEqual(lib_id, self.ls_tcl_client._basic_library_id)
1384         self.assertEqual(TAS_INFO['ip'], self.ls_tcl_client.tcl_server_ip)
1385         self.assertEqual(auth[0], self.ls_tcl_client._user)
1386         self.assertEqual(len(exec_responses),
1387                          self.mock_tcl_handler.execute.call_count)
1388         self.mock_tcl_handler.execute.assert_has_calls([
1389             mock.call("ls::login 1.1.1.1 user password"),
1390             mock.call("ls::get [ls::query LibraryInfo -userLibraryName user] -Id"),
1391         ])
1392
1393     def test_connect_login_failed(self, *args):
1394         exec_responses = ['Login failed']
1395         auth = ('user', 'password')
1396         self.mock_tcl_handler.execute.side_effect = exec_responses
1397         self.assertRaises(exceptions.LandslideTclException,
1398                           self.ls_tcl_client.connect,
1399                           TAS_INFO['ip'],
1400                           *auth)
1401         self.assertIsNone(self.ls_tcl_client._library_id)
1402         self.assertIsNone(self.ls_tcl_client._basic_library_id)
1403         self.assertIsNone(self.ls_tcl_client.tcl_server_ip)
1404         self.assertIsNone(self.ls_tcl_client._user)
1405         self.assertEqual(len(exec_responses),
1406                          self.mock_tcl_handler.execute.call_count)
1407         self.mock_tcl_handler.execute.assert_called_with(
1408             "ls::login 1.1.1.1 user password")
1409
1410     def test_disconnect(self, *args):
1411         self.ls_tcl_client.disconnect()
1412         self.mock_tcl_handler.execute.assert_called_once_with("ls::logout")
1413         self.assertIsNone(self.ls_tcl_client.tcl_server_ip)
1414         self.assertIsNone(self.ls_tcl_client._user)
1415         self.assertIsNone(self.ls_tcl_client._library_id)
1416         self.assertIsNone(self.ls_tcl_client._basic_library_id)
1417
1418     def test_create_test_server(self, *args):
1419         return_value = '2'
1420         self.ls_tcl_client._ts_context.vnfd_helper = \
1421             VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1422         self.ls_tcl_client._ts_context.license_data = {'lic_id': return_value}
1423         self.mock_tcl_handler.execute.return_value = return_value
1424         self.ls_tcl_client._set_thread_model = mock.Mock()
1425         res = self.ls_tcl_client.create_test_server(TEST_SERVERS[1])
1426         self.assertEqual(3, self.mock_tcl_handler.execute.call_count)
1427         self.mock_tcl_handler.execute.assert_has_calls([
1428             mock.call('ls::query TsId TestServer_2'),
1429             mock.call('set ts [ls::retrieve TsInfo -Name "TestServer_2"]'),
1430             mock.call('ls::get $ts -RequestedLicense'),
1431         ])
1432         self.ls_tcl_client._set_thread_model.assert_called_once_with(
1433             TEST_SERVERS[1]['name'],
1434             TEST_SERVERS[1]['thread_model'])
1435         self.assertEqual(int(return_value), res)
1436
1437     def test_create_test_server_fail_limit_reach(self, *args):
1438         self.mock_tcl_handler.execute.side_effect = ['TS not found',
1439                                                      'Add failed']
1440         self.assertRaises(RuntimeError,
1441                           self.ls_tcl_client.create_test_server,
1442                           TEST_SERVERS[0])
1443         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1444         self.mock_tcl_handler.execute.assert_has_calls([
1445             mock.call('ls::query TsId TestServer_1'),
1446             mock.call('ls::perform AddTs -Name "TestServer_1" '
1447                       '-Ip "192.168.122.101"'),
1448         ])
1449
1450     def test__add_test_server(self):
1451         ts_id = '2'
1452         self.mock_tcl_handler.execute.side_effect = ['TS not found', ts_id]
1453         self.assertEqual(ts_id,
1454                          self.ls_tcl_client._add_test_server('name', 'ip'))
1455         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1456         self.mock_tcl_handler.execute.assert_has_calls([
1457             mock.call('ls::query TsId name'),
1458             mock.call('ls::perform AddTs -Name "name" -Ip "ip"'),
1459         ])
1460
1461     def test__add_test_server_failed(self):
1462         self.mock_tcl_handler.execute.side_effect = ['TS not found',
1463                                                      'Add failed']
1464         self.assertRaises(RuntimeError, self.ls_tcl_client._add_test_server,
1465                           'name', 'ip')
1466         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1467         self.mock_tcl_handler.execute.assert_has_calls([
1468             mock.call('ls::query TsId name'),
1469             mock.call('ls::perform AddTs -Name "name" -Ip "ip"'),
1470         ])
1471
1472     def test__update_license(self):
1473         curr_lic_id = '111'
1474         new_lic_id = '222'
1475         exec_resp = ['java0x4',
1476                      curr_lic_id,
1477                      TCL_SUCCESS_RESPONSE,
1478                      TCL_SUCCESS_RESPONSE]
1479         self.ls_tcl_client._ts_context.license_data = {'lic_id': new_lic_id}
1480         self.mock_tcl_handler.execute.side_effect = exec_resp
1481         self.ls_tcl_client._update_license('name')
1482         self.assertEqual(len(exec_resp),
1483                          self.mock_tcl_handler.execute.call_count)
1484
1485         self.mock_tcl_handler.execute.assert_has_calls([
1486             mock.call('set ts [ls::retrieve TsInfo -Name "name"]'),
1487             mock.call('ls::get $ts -RequestedLicense'),
1488             mock.call('ls::config $ts -RequestedLicense 222'),
1489             mock.call('ls::perform ModifyTs $ts'),
1490         ])
1491
1492     def test__update_license_same_as_current(self):
1493         curr_lic_id = '111'
1494         new_lic_id = '111'
1495         exec_resp = ['java0x4', curr_lic_id]
1496         self.ls_tcl_client._ts_context.license_data = {'lic_id': new_lic_id}
1497         self.mock_tcl_handler.execute.side_effect = exec_resp
1498         self.ls_tcl_client._update_license('name')
1499         self.assertEqual(len(exec_resp),
1500                          self.mock_tcl_handler.execute.call_count)
1501         self.mock_tcl_handler.execute.assert_has_calls([
1502             mock.call('set ts [ls::retrieve TsInfo -Name "name"]'),
1503             mock.call('ls::get $ts -RequestedLicense'),
1504         ])
1505
1506     def test__set_thread_model_update_needed(self):
1507         self.ls_tcl_client._ts_context.vnfd_helper = {
1508             'mgmt-interface': {
1509                 'cfguser_password': 'cfguser_password'
1510             }
1511         }
1512         exec_resp = ['java0x4', 'V0', '', '']
1513         self.mock_tcl_handler.execute.side_effect = exec_resp
1514         self.ls_tcl_client._set_thread_model('name', 'Fireball')
1515         self.assertEqual(len(exec_resp),
1516                          self.mock_tcl_handler.execute.call_count)
1517         self.mock_tcl_handler.execute.assert_has_calls([
1518             mock.call('set tsc [ls::perform RetrieveTsConfiguration '
1519                       '-name "name" cfguser_password]'),
1520             mock.call('ls::get $tsc -ThreadModel'),
1521             mock.call('ls::config $tsc -ThreadModel "V1_FB3"'),
1522             mock.call('ls::perform ApplyTsConfiguration $tsc cfguser_password'),
1523         ])
1524
1525     def test__set_thread_model_no_update_needed(self):
1526         self.ls_tcl_client._ts_context.vnfd_helper = {
1527             'mgmt-interface': {
1528                 'cfguser_password': 'cfguser_password'
1529             }
1530         }
1531         exec_resp = ['java0x4', 'V0']
1532         self.mock_tcl_handler.execute.side_effect = exec_resp
1533         self.ls_tcl_client._set_thread_model('name', 'Legacy')
1534         self.assertEqual(len(exec_resp),
1535                          self.mock_tcl_handler.execute.call_count)
1536         self.mock_tcl_handler.execute.assert_has_calls([
1537             mock.call('set tsc [ls::perform RetrieveTsConfiguration '
1538                       '-name "name" cfguser_password]'),
1539             mock.call('ls::get $tsc -ThreadModel'),
1540         ])
1541
1542     @mock.patch.object(tg_landslide.LandslideTclClient,
1543                        'resolve_test_server_name', side_effect=['4', '2'])
1544     def test_create_test_session(self, *args):
1545         _session_profile = copy.deepcopy(SESSION_PROFILE)
1546         _session_profile['reservations'] = RESERVATIONS
1547         self.ls_tcl_client._save_test_session = mock.Mock()
1548         self.ls_tcl_client._configure_ts_group = mock.Mock()
1549         self.ls_tcl_client._library_id = 42
1550         self.ls_tcl_client.create_test_session(_session_profile)
1551         self.assertEqual(17, self.mock_tcl_handler.execute.call_count)
1552         self.mock_tcl_handler.execute.assert_has_calls([
1553             mock.call('set test_ [ls::create TestSession]'),
1554             mock.call('ls::config $test_ -Library 42 '
1555                       '-Name "default_bearer_capacity"'),
1556             mock.call('ls::config $test_ -Description ' \
1557                       '"UE default bearer creation test case"'),
1558             mock.call('ls::config $test_ -Keywords ""'),
1559             mock.call('ls::config $test_ -Duration "60"'),
1560             mock.call('ls::config $test_ -Iterations "1"'),
1561             # _configure_reservation
1562             mock.call('set reservation_ [ls::create Reservation -under $test_]'),
1563             mock.call('ls::config $reservation_ -TsIndex 0 '
1564                       '-TsId 4 -TsName "TestServer_1"'),
1565             mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'),
1566             mock.call('ls::config $physubnet_ -Name "eth1" -Base "10.42.32.100" '
1567                       '-Mask "/24" -NumIps 20'),
1568             # _configure_reservation
1569             mock.call('set reservation_ [ls::create Reservation -under $test_]'),
1570             mock.call('ls::config $reservation_ -TsIndex 1 '
1571                       '-TsId 2 -TsName "TestServer_2"'),
1572             mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'),
1573             mock.call('ls::config $physubnet_ -Name "eth1" -Base "10.42.32.1" '
1574                       '-Mask "/24" -NumIps 100'),
1575             mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'),
1576             mock.call('ls::config $physubnet_ -Name "eth2" -Base "10.42.33.1" '
1577                       '-Mask "/24" -NumIps 100'),
1578             # _configure_report_options
1579             mock.call('ls::config $test_.ReportOptions -Format 1 -Ts -3 -Tc -3'),
1580         ])
1581
1582     def test_create_dmf(self):
1583         self.mock_tcl_handler.execute.return_value = '2'
1584         self.ls_tcl_client._save_dmf = mock.Mock()
1585         self.ls_tcl_client.create_dmf(copy.deepcopy(DMF_CFG))
1586         self.assertEqual(6, self.mock_tcl_handler.execute.call_count)
1587         # This is needed because the dictionary is unordered and the arguments
1588         # can come in either order
1589         call1 = mock.call(
1590             'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"')
1591         call2 = mock.call(
1592             'ls::config $dmf_ -isClientPortRange "false" -clientPort 2002')
1593         self.assertTrue(
1594             call1 in self.mock_tcl_handler.execute.mock_calls or
1595             call2 in self.mock_tcl_handler.execute.mock_calls)
1596
1597         self.mock_tcl_handler.execute.assert_has_calls([
1598             mock.call('set dmf_ [ls::create Dmf]'),
1599             mock.call(
1600                 'ls::get [ls::query LibraryInfo -systemLibraryName test] -Id'),
1601             mock.call('ls::config $dmf_ -Library 2 -Name "Basic UDP"'),
1602             mock.call('ls::config $dmf_ -dataProtocol "udp"'),
1603             # mock.call(
1604             #    'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"'),
1605             mock.call('ls::config $dmf_ -serverPort 2003'),
1606         ], any_order=True)
1607
1608     def test_configure_dmf(self):
1609         self.mock_tcl_handler.execute.return_value = '2'
1610         self.ls_tcl_client._save_dmf = mock.Mock()
1611         self.ls_tcl_client.configure_dmf(DMF_CFG)
1612         self.assertEqual(6, self.mock_tcl_handler.execute.call_count)
1613         # This is need because the dictionary is unordered and the arguments
1614         # can come in either order
1615         call1 = mock.call(
1616             'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"')
1617         call2 = mock.call(
1618             'ls::config $dmf_ -isClientPortRange "false" -clientPort 2002')
1619         self.assertTrue(
1620             call1 in self.mock_tcl_handler.execute.mock_calls or
1621             call2 in self.mock_tcl_handler.execute.mock_calls)
1622
1623         self.mock_tcl_handler.execute.assert_has_calls([
1624             mock.call('set dmf_ [ls::create Dmf]'),
1625             mock.call(
1626                 'ls::get [ls::query LibraryInfo -systemLibraryName test] -Id'),
1627             mock.call('ls::config $dmf_ -Library 2 -Name "Basic UDP"'),
1628             mock.call('ls::config $dmf_ -dataProtocol "udp"'),
1629             # mock.call(
1630             #    'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"'),
1631             mock.call('ls::config $dmf_ -serverPort 2003'),
1632         ], any_order=True)
1633
1634     def test_delete_dmf(self):
1635         self.assertRaises(NotImplementedError,
1636                           self.ls_tcl_client.delete_dmf,
1637                           DMF_CFG)
1638
1639     def test__save_dmf_valid(self):
1640         exec_resp = [TCL_SUCCESS_RESPONSE, TCL_SUCCESS_RESPONSE]
1641         self.mock_tcl_handler.execute.side_effect = exec_resp
1642         self.ls_tcl_client._save_dmf()
1643         self.assertEqual(len(exec_resp),
1644                          self.mock_tcl_handler.execute.call_count)
1645         self.mock_tcl_handler.execute.assert_has_calls([
1646            mock.call('ls::perform Validate -Dmf $dmf_'),
1647            mock.call('ls::save $dmf_ -overwrite'),
1648         ])
1649
1650     def test__save_dmf_invalid(self):
1651         exec_resp = ['Invalid', 'List of errors and warnings']
1652         self.mock_tcl_handler.execute.side_effect = exec_resp
1653         self.assertRaises(exceptions.LandslideTclException,
1654                           self.ls_tcl_client._save_dmf)
1655         self.assertEqual(len(exec_resp),
1656                          self.mock_tcl_handler.execute.call_count)
1657         self.mock_tcl_handler.execute.assert_has_calls([
1658            mock.call('ls::perform Validate -Dmf $dmf_'),
1659            mock.call('ls::get $dmf_ -ErrorsAndWarnings'),
1660         ])
1661
1662     def test__configure_report_options(self):
1663         _options = {'format': 'CSV', 'PerInterval': 'false'}
1664         self.ls_tcl_client._configure_report_options(_options)
1665         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1666         self.mock_tcl_handler.execute.assert_has_calls([
1667            mock.call('ls::config $test_.ReportOptions -Format 1 -Ts -3 -Tc -3'),
1668            mock.call('ls::config $test_.ReportOptions -PerInterval false'),
1669            ],
1670            any_order=True)
1671
1672     def test___configure_ts_group(self, *args):
1673         _ts_group = copy.deepcopy(SESSION_PROFILE['tsGroups'][0])
1674         self.ls_tcl_client._configure_tc_type = mock.Mock()
1675         self.ls_tcl_client._configure_preresolved_arp = mock.Mock()
1676         self.ls_tcl_client.resolve_test_server_name = mock.Mock(
1677             return_value='2')
1678         self.ls_tcl_client._configure_ts_group(_ts_group, 0)
1679         self.mock_tcl_handler.execute.assert_called_once_with(
1680             'set tss_ [ls::create TsGroup -under $test_ -tsId 2 ]')
1681
1682     def test___configure_ts_group_resolve_ts_fail(self, *args):
1683         _ts_group = copy.deepcopy(SESSION_PROFILE['tsGroups'][0])
1684         self.ls_tcl_client._configure_tc_type = mock.Mock()
1685         self.ls_tcl_client._configure_preresolved_arp = mock.Mock()
1686         self.ls_tcl_client.resolve_test_server_name = mock.Mock(
1687             return_value='TS Not Found')
1688         self.assertRaises(RuntimeError, self.ls_tcl_client._configure_ts_group,
1689                           _ts_group, 0)
1690         self.mock_tcl_handler.execute.assert_not_called()
1691
1692     def test__configure_tc_type(self):
1693         _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0])
1694         self.mock_tcl_handler.execute.return_value = TCL_SUCCESS_RESPONSE
1695         self.ls_tcl_client._configure_parameters = mock.Mock()
1696         self.ls_tcl_client._configure_tc_type(_tc, 0)
1697         self.assertEqual(7, self.mock_tcl_handler.execute.call_count)
1698
1699     def test__configure_tc_type_optional_param_omitted(self):
1700         _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0])
1701         del _tc['linked']
1702         self.mock_tcl_handler.execute.return_value = TCL_SUCCESS_RESPONSE
1703         self.ls_tcl_client._configure_parameters = mock.Mock()
1704         self.ls_tcl_client._configure_tc_type(_tc, 0)
1705         self.assertEqual(6, self.mock_tcl_handler.execute.call_count)
1706
1707     def test__configure_tc_type_wrong_type(self):
1708         _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0])
1709         _tc['type'] = 'not_supported'
1710         self.ls_tcl_client._configure_parameters = mock.Mock()
1711         self.assertRaises(RuntimeError,
1712                           self.ls_tcl_client._configure_tc_type,
1713                           _tc, 0)
1714         self.mock_tcl_handler.assert_not_called()
1715
1716     def test__configure_tc_type_not_found_basic_lib(self):
1717         _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0])
1718         self.ls_tcl_client._configure_parameters = mock.Mock()
1719         self.mock_tcl_handler.execute.return_value = 'Invalid'
1720         self.assertRaises(RuntimeError,
1721                           self.ls_tcl_client._configure_tc_type,
1722                           _tc, 0)
1723
1724     def test__configure_parameters(self):
1725         _params = copy.deepcopy(
1726             SESSION_PROFILE['tsGroups'][0]['testCases'][0]['parameters'])
1727         self.ls_tcl_client._configure_parameters(_params)
1728         self.assertEqual(16, self.mock_tcl_handler.execute.call_count)
1729
1730     def test__configure_array_param(self):
1731         _array = {"class": "Array",
1732                   "array": ["0"]}
1733         self.ls_tcl_client._configure_array_param('name', _array)
1734         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1735         self.mock_tcl_handler.execute.assert_has_calls([
1736             mock.call('ls::create -Array-name -under $p_ ;'),
1737             mock.call('ls::create ArrayItem -under $p_.name -Value "0"'),
1738         ])
1739
1740     def test__configure_test_node_param(self):
1741         _params = copy.deepcopy(
1742             SESSION_PROFILE['tsGroups'][0]['testCases'][0]['parameters'])
1743         self.ls_tcl_client._configure_test_node_param('SgwUserAddr',
1744                                                       _params['SgwUserAddr'])
1745         cmd = ('ls::create -TestNode-SgwUserAddr -under $p_ -Type "eth" '
1746         '-Phy "eth1" -Ip "SGW_USER_IP" -NumLinksOrNodes 1 '
1747         '-NextHop "SGW_CONTROL_NEXT_HOP" -Mac "" -MTU 1500 '
1748         '-ForcedEthInterface "" -EthStatsEnabled false -VlanId 0 '
1749         '-VlanUserPriority 0 -NumVlan 1 -UniqueVlanAddr false;')
1750         self.mock_tcl_handler.execute.assert_called_once_with(cmd)
1751
1752     def test__configure_sut_param(self):
1753         _params = {'name': 'name'}
1754         self.ls_tcl_client._configure_sut_param('name', _params)
1755         self.mock_tcl_handler.execute.assert_called_once_with(
1756             'ls::create -Sut-name -under $p_ -Name "name";')
1757
1758     def test__configure_dmf_param(self):
1759         _params = {"mainflows": [{"library": '111',
1760                                   "name": "Basic UDP"}],
1761                    "instanceGroups": [{
1762                        "mainflowIdx": 0,
1763                        "mixType": "",
1764                        "rate": 0.0,
1765                        "rows": [{
1766                            "clientPort": 0,
1767                            "context": 0,
1768                            "node": 0,
1769                            "overridePort": "false",
1770                            "ratingGroup": 0,
1771                            "role": 0,
1772                            "serviceId": 0,
1773                            "transport": "Any"}]
1774                    }]}
1775         self.ls_tcl_client._get_library_id = mock.Mock(return_value='111')
1776         res = self.ls_tcl_client._configure_dmf_param('name', _params)
1777         self.assertEqual(5, self.mock_tcl_handler.execute.call_count)
1778         self.assertIsNone(res)
1779         self.mock_tcl_handler.execute.assert_has_calls([
1780             mock.call('ls::create -Dmf-name -under $p_ ;'),
1781             mock.call('ls::perform AddDmfMainflow $p_.Dmf 111 "Basic UDP"'),
1782             mock.call('ls::config $p_.Dmf.InstanceGroup(0) -mixType '),
1783             mock.call('ls::config $p_.Dmf.InstanceGroup(0) -rate 0.0'),
1784             mock.call('ls::config $p_.Dmf.InstanceGroup(0).Row(0) -Node 0 '
1785                       '-OverridePort false -ClientPort 0 -Context 0 -Role 0 '
1786                       '-PreferredTransport Any -RatingGroup 0 '
1787                       '-ServiceID 0'),
1788         ])
1789
1790     def test__configure_dmf_param_no_instance_groups(self):
1791         _params = {"mainflows": [{"library": '111',
1792                                   "name": "Basic UDP"}]}
1793         self.ls_tcl_client._get_library_id = mock.Mock(return_value='111')
1794         res = self.ls_tcl_client._configure_dmf_param('name', _params)
1795         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1796         self.assertIsNone(res)
1797         self.mock_tcl_handler.execute.assert_has_calls([
1798             mock.call('ls::create -Dmf-name -under $p_ ;'),
1799             mock.call('ls::perform AddDmfMainflow $p_.Dmf 111 "Basic UDP"'),
1800         ])
1801
1802     def test__configure_reservation(self):
1803         _reservation = copy.deepcopy(RESERVATIONS[0])
1804         self.ls_tcl_client.resolve_test_server_name = mock.Mock(
1805             return_value='4')
1806         res = self.ls_tcl_client._configure_reservation(_reservation)
1807         self.assertIsNone(res)
1808         self.assertEqual(4, self.mock_tcl_handler.execute.call_count)
1809         self.mock_tcl_handler.execute.assert_has_calls([
1810             mock.call('set reservation_ [ls::create Reservation -under $test_]'),
1811             mock.call('ls::config $reservation_ -TsIndex 0 -TsId 4 ' + \
1812                       '-TsName "TestServer_1"'),
1813             mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'),
1814             mock.call('ls::config $physubnet_ -Name "eth1" ' + \
1815                       '-Base "10.42.32.100" -Mask "/24" -NumIps 20'),
1816         ])
1817
1818     def test__configure_preresolved_arp(self):
1819         _arp = [{'StartingAddress': '10.81.1.10',
1820                  'NumNodes': 1}]
1821         res = self.ls_tcl_client._configure_preresolved_arp(_arp)
1822         self.mock_tcl_handler.execute.assert_called_once()
1823         self.assertIsNone(res)
1824         self.mock_tcl_handler.execute.assert_called_once_with(
1825             'ls::create PreResolvedArpAddress -under $tss_ ' + \
1826             '-StartingAddress "10.81.1.10" -NumNodes 1')
1827
1828     def test__configure_preresolved_arp_none(self):
1829         res = self.ls_tcl_client._configure_preresolved_arp(None)
1830         self.assertIsNone(res)
1831         self.mock_tcl_handler.execute.assert_not_called()
1832
1833     def test_delete_test_session(self):
1834         self.assertRaises(NotImplementedError,
1835                           self.ls_tcl_client.delete_test_session, {})
1836
1837     def test__save_test_session(self):
1838         self.mock_tcl_handler.execute.side_effect = [TCL_SUCCESS_RESPONSE,
1839                                                      TCL_SUCCESS_RESPONSE]
1840         res = self.ls_tcl_client._save_test_session()
1841         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1842         self.assertIsNone(res)
1843         self.mock_tcl_handler.execute.assert_has_calls([
1844             mock.call('ls::perform Validate -TestSession $test_'),
1845             mock.call('ls::save $test_ -overwrite'),
1846         ])
1847
1848     def test__save_test_session_invalid(self):
1849         self.mock_tcl_handler.execute.side_effect = ['Invalid', 'Errors']
1850         self.assertRaises(exceptions.LandslideTclException,
1851                           self.ls_tcl_client._save_test_session)
1852         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1853         self.mock_tcl_handler.execute.assert_has_calls([
1854             mock.call('ls::perform Validate -TestSession $test_'),
1855             mock.call('ls::get $test_ -ErrorsAndWarnings'),
1856         ])
1857
1858     def test__get_library_id_system_lib(self):
1859         self.mock_tcl_handler.execute.return_value = '111'
1860         res = self.ls_tcl_client._get_library_id('name')
1861         self.mock_tcl_handler.execute.assert_called_once()
1862         self.assertEqual('111', res)
1863         self.mock_tcl_handler.execute.assert_called_with(
1864             'ls::get [ls::query LibraryInfo -systemLibraryName name] -Id')
1865
1866     def test__get_library_id_user_lib(self):
1867         self.mock_tcl_handler.execute.side_effect = ['Not found', '222']
1868         res = self.ls_tcl_client._get_library_id('name')
1869         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1870         self.assertEqual('222', res)
1871         self.mock_tcl_handler.execute.assert_has_calls([
1872             mock.call(
1873                 'ls::get [ls::query LibraryInfo -systemLibraryName name] -Id'),
1874             mock.call(
1875                 'ls::get [ls::query LibraryInfo -userLibraryName name] -Id'),
1876         ])
1877
1878     def test__get_library_id_exception(self):
1879         self.mock_tcl_handler.execute.side_effect = ['Not found', 'Not found']
1880         self.assertRaises(exceptions.LandslideTclException,
1881                           self.ls_tcl_client._get_library_id,
1882                           'name')
1883         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1884         self.mock_tcl_handler.execute.assert_has_calls([
1885             mock.call(
1886                 'ls::get [ls::query LibraryInfo -systemLibraryName name] -Id'),
1887             mock.call(
1888                 'ls::get [ls::query LibraryInfo -userLibraryName name] -Id'),
1889         ])
1890
1891
1892 class TestLsTclHandler(unittest.TestCase):
1893
1894     def setUp(self):
1895         self.mock_lsapi = mock.patch.object(tg_landslide, 'LsApi')
1896         self.mock_lsapi.start()
1897
1898         self.addCleanup(self._cleanup)
1899
1900     def _cleanup(self):
1901         self.mock_lsapi.stop()
1902
1903     def test___init__(self, *args):
1904         self.ls_tcl_handler = tg_landslide.LsTclHandler()
1905         self.assertEqual({}, self.ls_tcl_handler.tcl_cmds)
1906         self.ls_tcl_handler._ls.tcl.assert_called_once()
1907
1908     def test_execute(self, *args):
1909         self.ls_tcl_handler = tg_landslide.LsTclHandler()
1910         self.ls_tcl_handler.execute('command')
1911         self.assertIn('command', self.ls_tcl_handler.tcl_cmds)