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