Merge "[docs] Remove the VTC chapter in the userguide"
[yardstick.git] / yardstick / tests / unit / network_services / libs / ixia_libs / test_ixnet_api.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 mock
16 import IxNetwork
17 import unittest
18
19 from copy import deepcopy
20
21 from yardstick.common import exceptions
22 from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api
23
24
25 UPLINK = 'uplink'
26 DOWNLINK = 'downlink'
27
28 TRAFFIC_PARAMETERS = {
29     UPLINK: {
30         'id': 1,
31         'bidir': 'False',
32         'duration': 60,
33         'rate': 10000.5,
34         'rate_unit': 'fps',
35         'outer_l2': {
36             'framesize': {'64B': '25', '256B': '75'},
37             'QinQ': None
38         },
39         'outer_l3': {
40             'count': 512,
41             'seed': 1,
42             'dscp': 0,
43             'proto': 'udp',
44             'ttl': 32,
45             'dstip': '152.16.40.20',
46             'srcip': '152.16.100.20',
47             'dstmask': 24,
48             'srcmask': 24
49         },
50         'outer_l4': {
51             'seed': 1,
52             'count': 1,
53             'dstport': 2001,
54             'srcport': 1234,
55             'srcportmask': 0,
56             'dstportmask': 0
57         },
58         'traffic_type': 'continuous'
59     },
60     DOWNLINK: {
61         'id': 2,
62         'bidir': 'False',
63         'duration': 60,
64         'rate': 75.2,
65         'rate_unit': '%',
66         'outer_l2': {
67             'framesize': {'128B': '35', '1024B': '65'},
68             'QinQ': None
69         },
70         'outer_l3': {
71             'count': 1024,
72             'seed': 1,
73             'dscp': 0,
74             'proto': 'udp',
75             'ttl': 32,
76             'dstip': '2001::10',
77             'srcip': '2021::10',
78             'dstmask': 64,
79             'srcmask': 64
80         },
81         'outer_l4': {
82             'seed': 1,
83             'count': 1,
84             'dstport': 1234,
85             'srcport': 2001,
86             'srcportmask': 0,
87             'dstportmask': 0
88         },
89         'traffic_type': 'continuous'
90     }
91 }
92
93
94 class TestIxNextgen(unittest.TestCase):
95
96     def setUp(self):
97         self.ixnet = mock.Mock()
98         self.ixnet.execute = mock.Mock()
99         self.ixnet.getRoot.return_value = 'my_root'
100         self.ixnet_gen = ixnet_api.IxNextgen()
101         self.ixnet_gen._ixnet = self.ixnet
102
103     def test_get_config(self):
104         tg_cfg = {
105             'vdu': [
106                 {
107                     'external-interface': [
108                         {'virtual-interface': {'vpci': '0000:07:00.1'}},
109                         {'virtual-interface': {'vpci': '0001:08:01.2'}}
110                     ]
111                 },
112             ],
113             'mgmt-interface': {
114                 'ip': 'test1',
115                 'tg-config': {
116                     'dut_result_dir': 'test2',
117                     'version': 'test3',
118                     'ixchassis': 'test4',
119                     'tcl_port': 'test5',
120                 },
121             }
122         }
123
124         expected = {
125             'machine': 'test1',
126             'port': 'test5',
127             'chassis': 'test4',
128             'cards': ['0000', '0001'],
129             'ports': ['07', '08'],
130             'output_dir': 'test2',
131             'version': 'test3',
132             'bidir': True,
133         }
134
135         result = ixnet_api.IxNextgen.get_config(tg_cfg)
136         self.assertEqual(result, expected)
137
138     def test__get_config_element_by_flow_group_name(self):
139         self.ixnet_gen._ixnet.getList.side_effect = [['traffic_item'],
140                                                      ['fg_01']]
141         self.ixnet_gen._ixnet.getAttribute.return_value = 'flow_group_01'
142         output = self.ixnet_gen._get_config_element_by_flow_group_name(
143             'flow_group_01')
144         self.assertEqual('traffic_item/configElement:flow_group_01', output)
145
146     def test__get_config_element_by_flow_group_name_no_match(self):
147         self.ixnet_gen._ixnet.getList.side_effect = [['traffic_item'],
148                                                      ['fg_01']]
149         self.ixnet_gen._ixnet.getAttribute.return_value = 'flow_group_02'
150         output = self.ixnet_gen._get_config_element_by_flow_group_name(
151             'flow_group_01')
152         self.assertIsNone(output)
153
154     def test__get_stack_item(self):
155         self.ixnet_gen._ixnet.getList.return_value = ['tcp1', 'tcp2', 'udp']
156         with mock.patch.object(
157                 self.ixnet_gen, '_get_config_element_by_flow_group_name') as \
158                 mock_get_cfg_element:
159             mock_get_cfg_element.return_value = 'cfg_element'
160             output = self.ixnet_gen._get_stack_item(mock.ANY, ixnet_api.PROTO_TCP)
161         self.assertEqual(['tcp1', 'tcp2'], output)
162
163     def test__get_stack_item_no_config_element(self):
164         with mock.patch.object(
165                 self.ixnet_gen, '_get_config_element_by_flow_group_name',
166                 return_value=None):
167             with self.assertRaises(exceptions.IxNetworkFlowNotPresent):
168                 self.ixnet_gen._get_stack_item(mock.ANY, mock.ANY)
169
170     def test__get_field_in_stack_item(self):
171         self.ixnet_gen._ixnet.getList.return_value = ['field1', 'field2']
172         output = self.ixnet_gen._get_field_in_stack_item(mock.ANY, 'field2')
173         self.assertEqual('field2', output)
174
175     def test__get_field_in_stack_item_no_field_present(self):
176         self.ixnet_gen._ixnet.getList.return_value = ['field1', 'field2']
177         with self.assertRaises(exceptions.IxNetworkFieldNotPresentInStackItem):
178             self.ixnet_gen._get_field_in_stack_item(mock.ANY, 'field3')
179
180     def test__parse_framesize(self):
181         framesize = {'64B': '75', '512b': '25'}
182         output = self.ixnet_gen._parse_framesize(framesize)
183         self.assertEqual(2, len(output))
184         self.assertIn([64, 64, 75], output)
185         self.assertIn([512, 512, 25], output)
186
187     @mock.patch.object(IxNetwork, 'IxNet')
188     def test_connect(self, mock_ixnet):
189         mock_ixnet.return_value = self.ixnet
190         with mock.patch.object(self.ixnet_gen, 'get_config') as mock_config:
191             mock_config.return_value = {'machine': 'machine_fake',
192                                         'port': 'port_fake',
193                                         'version': 12345}
194             self.ixnet_gen.connect(mock.ANY)
195
196         self.ixnet.connect.assert_called_once_with(
197             'machine_fake', '-port', 'port_fake', '-version', '12345')
198         mock_config.assert_called_once()
199
200     def test_connect_invalid_config_no_machine(self):
201         self.ixnet_gen.get_config = mock.Mock(return_value={
202             'port': 'port_fake',
203             'version': '12345'})
204         self.assertRaises(KeyError, self.ixnet_gen.connect, mock.ANY)
205         self.ixnet.connect.assert_not_called()
206
207     def test_connect_invalid_config_no_port(self):
208         self.ixnet_gen.get_config = mock.Mock(return_value={
209             'machine': 'machine_fake',
210             'version': '12345'})
211         self.assertRaises(KeyError, self.ixnet_gen.connect, mock.ANY)
212         self.ixnet.connect.assert_not_called()
213
214     def test_connect_invalid_config_no_version(self):
215         self.ixnet_gen.get_config = mock.Mock(return_value={
216             'machine': 'machine_fake',
217             'port': 'port_fake'})
218         self.assertRaises(KeyError, self.ixnet_gen.connect, mock.ANY)
219         self.ixnet.connect.assert_not_called()
220
221     def test_connect_no_config(self):
222         self.ixnet_gen.get_config = mock.Mock(return_value={})
223         self.assertRaises(KeyError, self.ixnet_gen.connect, mock.ANY)
224         self.ixnet.connect.assert_not_called()
225
226     def test_clear_config(self):
227         self.ixnet_gen.clear_config()
228         self.ixnet.execute.assert_called_once_with('newConfig')
229
230     @mock.patch.object(ixnet_api, 'log')
231     def test_assign_ports_2_ports(self, *args):
232         self.ixnet.getAttribute.side_effect = ['up', 'down']
233         config = {
234             'chassis': '1.1.1.1',
235             'cards': ['1', '2'],
236             'ports': ['2', '2']}
237         self.ixnet_gen._cfg = config
238
239         self.assertIsNone(self.ixnet_gen.assign_ports())
240         self.assertEqual(self.ixnet.execute.call_count, 2)
241         self.assertEqual(self.ixnet.commit.call_count, 4)
242         self.assertEqual(self.ixnet.getAttribute.call_count, 2)
243
244     @mock.patch.object(ixnet_api, 'log')
245     def test_assign_ports_port_down(self, mock_log):
246         self.ixnet.getAttribute.return_value = 'down'
247         config = {
248             'chassis': '1.1.1.1',
249             'cards': ['1', '2'],
250             'ports': ['3', '4']}
251         self.ixnet_gen._cfg = config
252         self.ixnet_gen.assign_ports()
253         mock_log.warning.assert_called()
254
255     def test_assign_ports_no_config(self):
256         self.ixnet_gen._cfg = {}
257         self.assertRaises(KeyError, self.ixnet_gen.assign_ports)
258
259     def test__create_traffic_item(self):
260         self.ixnet.add.return_value = 'my_new_traffic_item'
261         self.ixnet.remapIds.return_value = ['my_traffic_item_id']
262
263         self.ixnet_gen._create_traffic_item()
264         self.ixnet.add.assert_called_once_with(
265             'my_root/traffic', 'trafficItem')
266         self.ixnet.setMultiAttribute.assert_called_once_with(
267             'my_new_traffic_item', '-name', 'RFC2544', '-trafficType', 'raw')
268         self.assertEqual(2, self.ixnet.commit.call_count)
269         self.ixnet.remapIds.assert_called_once_with('my_new_traffic_item')
270         self.ixnet.setAttribute('my_traffic_item_id/tracking',
271                                 '-trackBy', 'trafficGroupId0')
272
273     def test__create_flow_groups(self):
274         self.ixnet_gen.ixnet.getList.side_effect = [['traffic_item'], ['1', '2']]
275         self.ixnet_gen.ixnet.add.side_effect = ['endp1', 'endp2']
276         self.ixnet_gen._create_flow_groups()
277         self.ixnet_gen.ixnet.add.assert_has_calls([
278             mock.call('traffic_item', 'endpointSet'),
279             mock.call('traffic_item', 'endpointSet')])
280         self.ixnet_gen.ixnet.setMultiAttribute.assert_has_calls([
281             mock.call('endp1', '-name', '1', '-sources', ['1/protocols'],
282                       '-destinations', ['2/protocols']),
283             mock.call('endp2', '-name', '2', '-sources', ['2/protocols'],
284                       '-destinations', ['1/protocols'])])
285
286     def test__append_protocol_to_stack(self):
287
288         self.ixnet_gen._append_procotol_to_stack('my_protocol', 'prev_element')
289         self.ixnet.execute.assert_called_with(
290             'append', 'prev_element',
291             'my_root/traffic/protocolTemplate:"my_protocol"')
292
293     def test__setup_config_elements(self):
294         self.ixnet_gen.ixnet.getList.side_effect = [['traffic_item'],
295                                                ['cfg_element']]
296         with mock.patch.object(self.ixnet_gen, '_append_procotol_to_stack') as \
297                 mock_append_proto:
298             self.ixnet_gen._setup_config_elements()
299         mock_append_proto.assert_has_calls([
300             mock.call(ixnet_api.PROTO_UDP, 'cfg_element/stack:"ethernet-1"'),
301             mock.call(ixnet_api.PROTO_IPV4, 'cfg_element/stack:"ethernet-1"')])
302         self.ixnet_gen.ixnet.setAttribute.assert_has_calls([
303             mock.call('cfg_element/frameRateDistribution', '-portDistribution',
304                       'splitRateEvenly'),
305             mock.call('cfg_element/frameRateDistribution',
306                       '-streamDistribution', 'splitRateEvenly')])
307
308     @mock.patch.object(ixnet_api.IxNextgen, '_create_traffic_item')
309     @mock.patch.object(ixnet_api.IxNextgen, '_create_flow_groups')
310     @mock.patch.object(ixnet_api.IxNextgen, '_setup_config_elements')
311     def test_create_traffic_model(self, mock__setup_config_elements,
312                                   mock__create_flow_groups,
313                                   mock__create_traffic_item):
314
315         self.ixnet_gen.create_traffic_model()
316         mock__create_traffic_item.assert_called_once()
317         mock__create_flow_groups.assert_called_once()
318         mock__setup_config_elements.assert_called_once()
319
320     def test__update_frame_mac(self):
321         with mock.patch.object(self.ixnet_gen, '_get_field_in_stack_item') as \
322                 mock_get_field:
323             mock_get_field.return_value = 'field_descriptor'
324             self.ixnet_gen._update_frame_mac('ethernet_descriptor', 'field', 'mac')
325         mock_get_field.assert_called_once_with('ethernet_descriptor', 'field')
326         self.ixnet_gen.ixnet.setMultiAttribute(
327             'field_descriptor', '-singleValue', 'mac', '-fieldValue', 'mac',
328             '-valueType', 'singleValue')
329         self.ixnet_gen.ixnet.commit.assert_called_once()
330
331     def test_update_frame(self):
332         with mock.patch.object(
333                 self.ixnet_gen, '_get_config_element_by_flow_group_name',
334                 return_value='cfg_element'), \
335                 mock.patch.object(self.ixnet_gen, '_update_frame_mac') as \
336                 mock_update_frame, \
337                 mock.patch.object(self.ixnet_gen, '_get_stack_item') as \
338                 mock_get_stack_item:
339             mock_get_stack_item.side_effect = [['item1'], ['item2'],
340                                                ['item3'], ['item4']]
341             self.ixnet_gen.update_frame(TRAFFIC_PARAMETERS, 50)
342
343         self.assertEqual(6, len(self.ixnet_gen.ixnet.setMultiAttribute.mock_calls))
344         self.assertEqual(4, len(mock_update_frame.mock_calls))
345
346         self.ixnet_gen.ixnet.setMultiAttribute.assert_has_calls([
347             mock.call('cfg_element/transmissionControl',
348                       '-type', 'continuous', '-duration', 50)
349         ])
350
351     def test_update_frame_qinq(self):
352         with mock.patch.object(self.ixnet_gen,
353                                '_get_config_element_by_flow_group_name',
354                                return_value='cfg_element'), \
355              mock.patch.object(self.ixnet_gen, '_update_frame_mac'),\
356              mock.patch.object(self.ixnet_gen, '_get_stack_item',
357                                return_value='item'), \
358              mock.patch.object(self.ixnet_gen, '_get_field_in_stack_item',
359                                return_value='field'):
360
361             traffic_parameters = deepcopy(TRAFFIC_PARAMETERS)
362             traffic_parameters[UPLINK]['outer_l2']['QinQ'] = {
363                 'S-VLAN': {'id': 128,
364                            'priority': 1,
365                            'cfi': 0},
366                 'C-VLAN': {'id': 512,
367                            'priority': 0,
368                            'cfi': 2}
369             }
370
371             self.ixnet_gen.update_frame(traffic_parameters, 50)
372
373         self.ixnet_gen.ixnet.setMultiAttribute.assert_has_calls([
374             mock.call('field', '-auto', 'false', '-singleValue', '0x88a8',
375                       '-fieldValue', '0x88a8', '-valueType', 'singleValue'),
376             mock.call('field', '-auto', 'false', '-singleValue', 1,
377                       '-fieldValue', 1, '-valueType', 'singleValue'),
378             mock.call('field', '-auto', 'false', '-singleValue', 128,
379                       '-fieldValue', 128, '-valueType', 'singleValue'),
380             mock.call('field', '-auto', 'false', '-singleValue', 512,
381                       '-fieldValue', 512, '-valueType', 'singleValue'),
382             mock.call('field', '-auto', 'false', '-singleValue', 2,
383                       '-fieldValue', 2, '-valueType', 'singleValue')
384         ], any_order=True)
385
386     def test_update_frame_flow_not_present(self):
387         with mock.patch.object(
388                 self.ixnet_gen, '_get_config_element_by_flow_group_name',
389                 return_value=None):
390             with self.assertRaises(exceptions.IxNetworkFlowNotPresent):
391                 self.ixnet_gen.update_frame(TRAFFIC_PARAMETERS, 40)
392
393     def test_get_statistics(self):
394         port_statistics = '::ixNet::OBJ-/statistics/view:"Port Statistics"'
395         flow_statistics = '::ixNet::OBJ-/statistics/view:"Flow Statistics"'
396         with mock.patch.object(self.ixnet_gen, '_build_stats_map') as \
397                 mock_build_stats:
398             self.ixnet_gen.get_statistics()
399
400         mock_build_stats.assert_has_calls([
401             mock.call(port_statistics, self.ixnet_gen.PORT_STATS_NAME_MAP),
402             mock.call(flow_statistics, self.ixnet_gen.LATENCY_NAME_MAP)])
403
404     def test__update_ipv4_address(self):
405         with mock.patch.object(self.ixnet_gen, '_get_field_in_stack_item',
406                                return_value='field_desc'):
407             self.ixnet_gen._update_ipv4_address(mock.ANY, mock.ANY, '192.168.1.1',
408                                            100, 26, 25)
409         self.ixnet_gen.ixnet.setMultiAttribute.assert_called_once_with(
410             'field_desc', '-seed', 100, '-fixedBits', '192.168.1.1',
411             '-randomMask', '0.0.0.63', '-valueType', 'random',
412             '-countValue', 25)
413
414     def test__update_udp_port(self):
415         with mock.patch.object(self.ixnet_gen, '_get_field_in_stack_item',
416                                return_value='field_desc'):
417             self.ixnet_gen._update_udp_port(mock.ANY, mock.ANY, 1234,
418                                             2, 0, 2)
419
420         self.ixnet_gen.ixnet.setMultiAttribute.assert_called_once_with(
421             'field_desc',
422             '-auto', 'false',
423             '-seed', 1,
424             '-fixedBits', 1234,
425             '-randomMask', 0,
426             '-valueType', 'random',
427             '-countValue', 1)
428
429     def test_update_ip_packet(self):
430         with mock.patch.object(self.ixnet_gen, '_update_ipv4_address') as \
431                 mock_update_add, \
432                 mock.patch.object(self.ixnet_gen, '_get_stack_item'), \
433                 mock.patch.object(self.ixnet_gen,
434                 '_get_config_element_by_flow_group_name', return_value='celm'):
435             self.ixnet_gen.update_ip_packet(TRAFFIC_PARAMETERS)
436
437         self.assertEqual(4, len(mock_update_add.mock_calls))
438
439     def test_update_ip_packet_exception_no_config_element(self):
440         with mock.patch.object(self.ixnet_gen,
441                                '_get_config_element_by_flow_group_name',
442                                return_value=None):
443             with self.assertRaises(exceptions.IxNetworkFlowNotPresent):
444                 self.ixnet_gen.update_ip_packet(TRAFFIC_PARAMETERS)
445
446     def test_update_l4(self):
447         with mock.patch.object(self.ixnet_gen, '_update_udp_port') as \
448                 mock_update_udp, \
449                 mock.patch.object(self.ixnet_gen, '_get_stack_item'), \
450                 mock.patch.object(self.ixnet_gen,
451                 '_get_config_element_by_flow_group_name', return_value='celm'):
452             self.ixnet_gen.update_l4(TRAFFIC_PARAMETERS)
453
454         self.assertEqual(4, len(mock_update_udp.mock_calls))
455
456     def test_update_l4_exception_no_config_element(self):
457         with mock.patch.object(self.ixnet_gen,
458                                '_get_config_element_by_flow_group_name',
459                                return_value=None):
460             with self.assertRaises(exceptions.IxNetworkFlowNotPresent):
461                 self.ixnet_gen.update_l4(TRAFFIC_PARAMETERS)
462
463     def test_update_l4_exception_no_supported_proto(self):
464         traffic_parameters = {
465             UPLINK: {
466                 'id': 1,
467                 'outer_l3': {
468                     'proto': 'unsupported',
469                 },
470             },
471         }
472         with mock.patch.object(self.ixnet_gen,
473                                '_get_config_element_by_flow_group_name',
474                                return_value='celm'):
475             with self.assertRaises(exceptions.IXIAUnsupportedProtocol):
476                 self.ixnet_gen.update_l4(traffic_parameters)
477
478     @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state')
479     def test_start_traffic(self, mock_ixnextgen_get_traffic_state):
480         self.ixnet_gen._ixnet.getList.return_value = [0]
481
482         mock_ixnextgen_get_traffic_state.side_effect = [
483             'stopped', 'started', 'started', 'started']
484
485         result = self.ixnet_gen.start_traffic()
486         self.assertIsNone(result)
487         self.ixnet.getList.assert_called_once()
488         self.assertEqual(3, self.ixnet_gen._ixnet.execute.call_count)
489
490     @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state')
491     def test_start_traffic_traffic_running(
492             self, mock_ixnextgen_get_traffic_state):
493         self.ixnet_gen._ixnet.getList.return_value = [0]
494         mock_ixnextgen_get_traffic_state.side_effect = [
495             'started', 'stopped', 'started']
496
497         result = self.ixnet_gen.start_traffic()
498         self.assertIsNone(result)
499         self.ixnet.getList.assert_called_once()
500         self.assertEqual(4, self.ixnet_gen._ixnet.execute.call_count)
501
502     @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state')
503     def test_start_traffic_wait_for_traffic_to_stop(
504             self, mock_ixnextgen_get_traffic_state):
505         self.ixnet_gen._ixnet.getList.return_value = [0]
506         mock_ixnextgen_get_traffic_state.side_effect = [
507             'started', 'started', 'started', 'stopped', 'started']
508
509         result = self.ixnet_gen.start_traffic()
510         self.assertIsNone(result)
511         self.ixnet.getList.assert_called_once()
512         self.assertEqual(4, self.ixnet_gen._ixnet.execute.call_count)
513
514     @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state')
515     def test_start_traffic_wait_for_traffic_start(
516             self, mock_ixnextgen_get_traffic_state):
517         self.ixnet_gen._ixnet.getList.return_value = [0]
518         mock_ixnextgen_get_traffic_state.side_effect = [
519             'stopped', 'stopped', 'stopped', 'started']
520
521         result = self.ixnet_gen.start_traffic()
522         self.assertIsNone(result)
523         self.ixnet.getList.assert_called_once()
524         self.assertEqual(3, self.ixnet_gen._ixnet.execute.call_count)