diff options
Diffstat (limited to 'yardstick')
34 files changed, 898 insertions, 212 deletions
diff --git a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py index 73311f0c2..a1af3c72b 100644 --- a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py +++ b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py @@ -46,7 +46,8 @@ class OvsDpdkContext(base.Context): '2.7.0': '16.11.1', '2.7.1': '16.11.2', '2.7.2': '16.11.3', - '2.8.0': '17.05.2' + '2.8.0': '17.05.2', + '2.8.1': '17.05.2' } DEFAULT_OVS = '2.6.0' @@ -145,8 +146,8 @@ class OvsDpdkContext(base.Context): cmd_list = [ "mkdir -p /usr/local/var/run/openvswitch", "mkdir -p {}".format(os.path.dirname(log_path)), - "ovsdb-server --remote=punix:/{0}/{1} --pidfile --detach".format(vpath, - ovs_sock_path), + ("ovsdb-server --remote=punix:/{0}/{1} --remote=ptcp:6640" + " --pidfile --detach").format(vpath, ovs_sock_path), ovs_other_config.format("--no-wait ", "dpdk-init=true"), ovs_other_config.format("--no-wait ", "dpdk-socket-mem='%s,%s'" % (socket0, socket1)), lcore_mask, @@ -166,8 +167,7 @@ class OvsDpdkContext(base.Context): version = self.ovs_properties.get('version', {}) ovs_ver = [int(x) for x in version.get('ovs', self.DEFAULT_OVS).split('.')] ovs_add_port = ('ovs-vsctl add-port {br} {port} -- ' - 'set Interface {port} type={type_}{dpdk_args}') - ovs_add_queue = 'ovs-vsctl set Interface {port} options:n_rxq={queue}' + 'set Interface {port} type={type_}{dpdk_args}{dpdk_rxq}') chmod_vpath = 'chmod 0777 {0}/var/run/openvswitch/dpdkvhostuser*' cmd_list = [ @@ -176,6 +176,8 @@ class OvsDpdkContext(base.Context): 'ovs-vsctl add-br {0} -- set bridge {0} datapath_type=netdev'. format(MAIN_BRIDGE) ] + dpdk_rxq = " options:n_rxq={queue}".format( + queue=self.ovs_properties.get("queues", 1)) ordered_network = collections.OrderedDict(self.networks) for index, vnf in enumerate(ordered_network.values()): @@ -183,10 +185,7 @@ class OvsDpdkContext(base.Context): dpdk_args = " options:dpdk-devargs=%s" % vnf.get("phy_port") dpdk_list.append(ovs_add_port.format( br=MAIN_BRIDGE, port='dpdk%s' % vnf.get("port_num", 0), - type_='dpdk', dpdk_args=dpdk_args)) - dpdk_list.append(ovs_add_queue.format( - port='dpdk%s' % vnf.get("port_num", 0), - queue=self.ovs_properties.get("queues", 1))) + type_='dpdk', dpdk_args=dpdk_args, dpdk_rxq=dpdk_rxq)) # Sorting the array to make sure we execute dpdk0... in the order list.sort(dpdk_list) @@ -196,7 +195,7 @@ class OvsDpdkContext(base.Context): for index, _ in enumerate(ordered_network): cmd_list.append(ovs_add_port.format( br=MAIN_BRIDGE, port='dpdkvhostuser%s' % index, - type_='dpdkvhostuser', dpdk_args="")) + type_='dpdkvhostuser', dpdk_args="", dpdk_rxq="")) ovs_flow = ("ovs-ofctl add-flow {0} in_port=%s,action=output:%s". format(MAIN_BRIDGE)) diff --git a/yardstick/benchmark/runners/duration.py b/yardstick/benchmark/runners/duration.py index 14fd8bb47..55c3690fd 100644 --- a/yardstick/benchmark/runners/duration.py +++ b/yardstick/benchmark/runners/duration.py @@ -106,7 +106,8 @@ def _worker_process(queue, cls, method_name, scenario_cfg, sequence += 1 - if (errors and sla_action is None) or time.time() > timeout or aborted.is_set(): + if ((errors and sla_action is None) or time.time() > timeout + or aborted.is_set() or benchmark.is_ended()): LOG.info("Worker END") break diff --git a/yardstick/benchmark/runners/proxduration.py b/yardstick/benchmark/runners/proxduration.py index 61a468fd3..e217904b9 100644 --- a/yardstick/benchmark/runners/proxduration.py +++ b/yardstick/benchmark/runners/proxduration.py @@ -112,7 +112,8 @@ def _worker_process(queue, cls, method_name, scenario_cfg, sequence += 1 - if (errors and sla_action is None) or time.time() > timeout or aborted.is_set(): + if ((errors and sla_action is None) or time.time() > timeout + or aborted.is_set() or benchmark.is_ended()): LOG.info("Worker END") break diff --git a/yardstick/benchmark/scenarios/base.py b/yardstick/benchmark/scenarios/base.py index 90a87ac29..1737bb942 100644 --- a/yardstick/benchmark/scenarios/base.py +++ b/yardstick/benchmark/scenarios/base.py @@ -50,6 +50,9 @@ class Scenario(object): def run(self, *args): """Entry point for scenario classes, called from runner worker""" + def is_ended(self): + return False + def teardown(self): """Default teardown implementation for Scenario classes""" pass diff --git a/yardstick/benchmark/scenarios/networking/vnf_generic.py b/yardstick/benchmark/scenarios/networking/vnf_generic.py index 6d68c5e64..d8f062522 100644 --- a/yardstick/benchmark/scenarios/networking/vnf_generic.py +++ b/yardstick/benchmark/scenarios/networking/vnf_generic.py @@ -63,6 +63,9 @@ class NetworkServiceTestCase(scenario_base.Scenario): self.bin_path = get_nsb_option('bin_path', '') self._mq_ids = [] + def is_ended(self): + return self.traffic_profile is not None and self.traffic_profile.is_ended() + def _get_ip_flow_range(self, ip_start_range): """Retrieve a CIDR first and last viable IPs @@ -158,8 +161,17 @@ class NetworkServiceTestCase(scenario_base.Scenario): tprofile_base.TrafficProfile.DOWNLINK: {}, 'extra_args': extra_args, 'duration': self._get_duration()} + traffic_vnfd = vnfdgen.generate_vnfd(tprofile, tprofile_data) - self.traffic_profile = tprofile_base.TrafficProfile.get(traffic_vnfd) + + traffic_config = \ + self.scenario_cfg.get("options", {}).get("traffic_config", {}) + + traffic_vnfd.setdefault("traffic_profile", {}) + traffic_vnfd["traffic_profile"].update(traffic_config) + + self.traffic_profile = \ + tprofile_base.TrafficProfile.get(traffic_vnfd) def _get_topology(self): topology = self.scenario_cfg["topology"] diff --git a/yardstick/benchmark/scenarios/parser/parser.py b/yardstick/benchmark/scenarios/parser/parser.py index 5b2b49c2c..a0f8e9e72 100644 --- a/yardstick/benchmark/scenarios/parser/parser.py +++ b/yardstick/benchmark/scenarios/parser/parser.py @@ -20,7 +20,7 @@ class Parser(base.Scenario): """running Parser Yang-to-Tosca module as a tool validating output against expected outcome - more info https://wiki.opnfv.org/parser + more info https://wiki.opnfv.org/display/parser """ __scenario_type__ = "Parser" diff --git a/yardstick/benchmark/scenarios/storage/storperf.py b/yardstick/benchmark/scenarios/storage/storperf.py index 8093cd2d2..e4c72dc8f 100644 --- a/yardstick/benchmark/scenarios/storage/storperf.py +++ b/yardstick/benchmark/scenarios/storage/storperf.py @@ -87,7 +87,9 @@ class StorPerf(base.Scenario): env_args = {} env_args_payload_list = ["agent_count", "agent_flavor", "public_network", "agent_image", - "volume_size"] + "volume_size", "volume_type", + "volume_count", "availability_zone", + "stack_name", "subnet_CIDR"] for env_argument in env_args_payload_list: try: @@ -213,11 +215,20 @@ class StorPerf(base.Scenario): # else: # time.sleep(int(esti_time)/2) - result_res = requests.get('http://%s:5000/api/v1.0/jobs?id=%s' % - (self.target, job_id)) + result_res = requests.get('http://%s:5000/api/v1.0/jobs?type=' + 'metadata&id=%s' % (self.target, job_id)) + result_res_content = jsonutils.loads(result_res.content) + if 'report' in result_res_content and \ + 'steady_state' in result_res_content['report']['details']: + res = result_res_content['report']['details']['steady_state'] + steady_state = res.values()[0] + LOG.info("Job %s completed with steady state %s", + job_id, steady_state) + + result_res = requests.get('http://%s:5000/api/v1.0/jobs?' + 'type=status&id=%s' % (self.target, job_id)) result_res_content = jsonutils.loads( result_res.content) - result.update(result_res_content) def initialize_disks(self): diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index 539e0fec3..5e0df973a 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -83,6 +83,10 @@ class InvalidType(YardstickException): message = 'Type "%(type_to_convert)s" is not valid' +class InvalidRxfFile(YardstickException): + message = 'Loaded rxf file has unexpected format' + + class InfluxDBConfigurationMissing(YardstickException): message = ('InfluxDB configuration is not available. Add "influxdb" as ' 'a dispatcher and the configuration section') diff --git a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py index 12f081dc6..556682b29 100644 --- a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py +++ b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2017 Intel Corporation +# Copyright (c) 2016-2018 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -41,12 +41,12 @@ C_VLAN = 1 ETHER_TYPE_802_1ad = '0x88a8' -IP_VERSION_4_MASK = 24 -IP_VERSION_6_MASK = 64 - TRAFFIC_STATUS_STARTED = 'started' TRAFFIC_STATUS_STOPPED = 'stopped' +PROTOCOL_STATUS_UP = 'up' +PROTOCOL_STATUS_DOWN = ['down', 'notStarted'] + SUPPORTED_PROTO = [PROTO_UDP] @@ -121,6 +121,11 @@ class IxNextgen(object): # pragma: no cover return self._ixnet raise exceptions.IxNetworkClientNotConnected() + def get_vports(self): + """Return the list of assigned ports (vport objects)""" + vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport') + return vports + def _get_config_element_by_flow_group_name(self, flow_group_name): """Get a config element using the flow group name @@ -175,6 +180,15 @@ class IxNextgen(object): # pragma: no cover return self.ixnet.getAttribute(self.ixnet.getRoot() + 'traffic', '-state') + def _get_protocol_status(self, proto): + """Get protocol status + + :param proto: IxNet protocol str representation, e.g.: + '::ixNet::OBJ-/topology:2/deviceGroup:1/ethernet:1/ipv4:L14' + :return: (str) protocol status: 'up', 'down' or 'notStarted' + """ + return self.ixnet.getAttribute(proto, '-sessionStatus')[0] + def is_traffic_running(self): """Returns true if traffic state == TRAFFIC_STATUS_STARTED""" return self._get_traffic_state() == TRAFFIC_STATUS_STARTED @@ -183,6 +197,28 @@ class IxNextgen(object): # pragma: no cover """Returns true if traffic state == TRAFFIC_STATUS_STOPPED""" return self._get_traffic_state() == TRAFFIC_STATUS_STOPPED + def is_protocols_running(self, protocols): + """Returns true if all protocols statuses are PROTOCOL_STATUS_UP + + :param protocols: list of protocols str representations, e.g.: + ['::ixNet::OBJ-/topology:2/deviceGroup:1/ethernet:1/ipv4:L14', ...] + :return: (bool) True if all protocols status is 'up', False if any + protocol status is 'down' or 'notStarted' + """ + return all(self._get_protocol_status(proto) == PROTOCOL_STATUS_UP + for proto in protocols) + + def is_protocols_stopped(self, protocols): + """Returns true if all protocols statuses are in PROTOCOL_STATUS_DOWN + + :param protocols: list of protocols str representations, e.g.: + ['::ixNet::OBJ-/topology:2/deviceGroup:1/ethernet:1/ipv4:L14', ...] + :return: (bool) True if all protocols status is 'down' or 'notStarted', + False if any protocol status is 'up' + """ + return all(self._get_protocol_status(proto) in PROTOCOL_STATUS_DOWN + for proto in protocols) + @staticmethod def _parse_framesize(framesize): """Parse "framesize" config param. to return a list of weighted pairs @@ -252,7 +288,7 @@ class IxNextgen(object): # pragma: no cover if self.ixnet.getAttribute(vport, '-state') != 'up': log.warning('Port %s is down', vport) - def _create_traffic_item(self): + def _create_traffic_item(self, traffic_type='raw'): """Create the traffic item to hold the flow groups The traffic item tracking by "Traffic Item" is enabled to retrieve the @@ -262,7 +298,7 @@ class IxNextgen(object): # pragma: no cover traffic_item = self.ixnet.add(self.ixnet.getRoot() + '/traffic', 'trafficItem') self.ixnet.setMultiAttribute(traffic_item, '-name', 'RFC2544', - '-trafficType', 'raw') + '-trafficType', traffic_type) self.ixnet.commit() traffic_item_id = self.ixnet.remapIds(traffic_item)[0] @@ -270,27 +306,25 @@ class IxNextgen(object): # pragma: no cover '-trackBy', 'trafficGroupId0') self.ixnet.commit() - def _create_flow_groups(self): - """Create the flow groups between the assigned ports""" + def _create_flow_groups(self, uplink, downlink): + """Create the flow groups between the endpoints""" traffic_item_id = self.ixnet.getList(self.ixnet.getRoot() + 'traffic', 'trafficItem')[0] log.info('Create the flow groups') - vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport') - uplink_ports = vports[::2] - downlink_ports = vports[1::2] + index = 0 - for up, down in zip(uplink_ports, downlink_ports): + for up, down in zip(uplink, downlink): log.info('FGs: %s <--> %s', up, down) endpoint_set_1 = self.ixnet.add(traffic_item_id, 'endpointSet') endpoint_set_2 = self.ixnet.add(traffic_item_id, 'endpointSet') self.ixnet.setMultiAttribute( endpoint_set_1, '-name', str(index + 1), - '-sources', [up + '/protocols'], - '-destinations', [down + '/protocols']) + '-sources', [up], + '-destinations', [down]) self.ixnet.setMultiAttribute( endpoint_set_2, '-name', str(index + 2), - '-sources', [down + '/protocols'], - '-destinations', [up + '/protocols']) + '-sources', [down], + '-destinations', [up]) self.ixnet.commit() index += 2 @@ -300,7 +334,7 @@ class IxNextgen(object): # pragma: no cover '/traffic/protocolTemplate:"{}"'.format(protocol_name)) self.ixnet.execute('append', previous_element, protocol) - def _setup_config_elements(self): + def _setup_config_elements(self, add_default_proto=True): """Setup the config elements The traffic item is configured to allow individual configurations per @@ -322,12 +356,13 @@ class IxNextgen(object): # pragma: no cover self.ixnet.setAttribute(config_element + '/frameRateDistribution', '-streamDistribution', 'splitRateEvenly') self.ixnet.commit() - self._append_procotol_to_stack( - PROTO_UDP, config_element + '/stack:"ethernet-1"') - self._append_procotol_to_stack( - PROTO_IPV4, config_element + '/stack:"ethernet-1"') + if add_default_proto: + self._append_procotol_to_stack( + PROTO_UDP, config_element + '/stack:"ethernet-1"') + self._append_procotol_to_stack( + PROTO_IPV4, config_element + '/stack:"ethernet-1"') - def create_traffic_model(self): + def create_traffic_model(self, uplink_ports, downlink_ports): """Create a traffic item and the needed flow groups Each flow group inside the traffic item (only one is present) @@ -338,10 +373,27 @@ class IxNextgen(object): # pragma: no cover FlowGroup3: port3 -> port4 FlowGroup4: port3 <- port4 """ - self._create_traffic_item() - self._create_flow_groups() + self._create_traffic_item('raw') + uplink_endpoints = [port + '/protocols' for port in uplink_ports] + downlink_endpoints = [port + '/protocols' for port in downlink_ports] + self._create_flow_groups(uplink_endpoints, downlink_endpoints) self._setup_config_elements() + def create_ipv4_traffic_model(self, uplink_topologies, downlink_topologies): + """Create a traffic item and the needed flow groups + + Each flow group inside the traffic item (only one is present) + represents the traffic between two topologies: + (uplink) (downlink) + FlowGroup1: uplink1 -> downlink1 + FlowGroup2: uplink1 <- downlink1 + FlowGroup3: uplink2 -> downlink2 + FlowGroup4: uplink2 <- downlink2 + """ + self._create_traffic_item('ipv4') + self._create_flow_groups(uplink_topologies, downlink_topologies) + self._setup_config_elements(False) + def _update_frame_mac(self, ethernet_descriptor, field, mac_address): """Set the MAC address in a config element stack Ethernet field @@ -385,16 +437,15 @@ class IxNextgen(object): # pragma: no cover raise exceptions.IxNetworkFlowNotPresent(flow_group=fg_id) type = traffic_param.get('traffic_type', 'fixedDuration') - rate = traffic_param['rate'] rate_unit = ( 'framesPerSecond' if traffic_param['rate_unit'] == tp_base.TrafficProfileConfig.RATE_FPS else 'percentLineRate') weighted_range_pairs = self._parse_framesize( - traffic_param['outer_l2']['framesize']) + traffic_param['outer_l2'].get('framesize', {})) srcmac = str(traffic_param['outer_l2'].get('srcmac', '00:00:00:00:00:01')) dstmac = str(traffic_param['outer_l2'].get('dstmac', '00:00:00:00:00:02')) - if traffic_param['outer_l2']['QinQ']: + if traffic_param['outer_l2'].get('QinQ'): s_vlan = traffic_param['outer_l2']['QinQ']['S-VLAN'] c_vlan = traffic_param['outer_l2']['QinQ']['C-VLAN'] @@ -419,21 +470,27 @@ class IxNextgen(object): # pragma: no cover self.ixnet.setMultiAttribute( config_element + '/transmissionControl', '-type', type, '-duration', duration) + self.ixnet.setMultiAttribute( config_element + '/frameRate', - '-rate', rate, '-type', rate_unit) - self.ixnet.setMultiAttribute( - config_element + '/frameSize', - '-type', 'weightedPairs', - '-weightedRangePairs', weighted_range_pairs) + '-rate', traffic_param['rate'], '-type', rate_unit) + + if len(weighted_range_pairs): + self.ixnet.setMultiAttribute( + config_element + '/frameSize', + '-type', 'weightedPairs', + '-weightedRangePairs', weighted_range_pairs) + self.ixnet.commit() - self._update_frame_mac( - self._get_stack_item(fg_id, PROTO_ETHERNET)[0], - 'destinationAddress', dstmac) - self._update_frame_mac( - self._get_stack_item(fg_id, PROTO_ETHERNET)[0], - 'sourceAddress', srcmac) + if dstmac: + self._update_frame_mac( + self._get_stack_item(fg_id, PROTO_ETHERNET)[0], + 'destinationAddress', dstmac) + if srcmac: + self._update_frame_mac( + self._get_stack_item(fg_id, PROTO_ETHERNET)[0], + 'sourceAddress', srcmac) def _update_vlan_tag(self, fg_id, params, vlan=0): field_to_param_map = { @@ -493,20 +550,24 @@ class IxNextgen(object): # pragma: no cover if not self._get_config_element_by_flow_group_name(fg_id): raise exceptions.IxNetworkFlowNotPresent(flow_group=fg_id) - count = traffic_param['outer_l3']['count'] - srcip = str(traffic_param['outer_l3']['srcip']) - dstip = str(traffic_param['outer_l3']['dstip']) - srcseed = traffic_param['outer_l3']['srcseed'] - dstseed = traffic_param['outer_l3']['dstseed'] - srcmask = traffic_param['outer_l3']['srcmask'] or IP_VERSION_4_MASK - dstmask = traffic_param['outer_l3']['dstmask'] or IP_VERSION_4_MASK - - self._update_ipv4_address( - self._get_stack_item(fg_id, PROTO_IPV4)[0], - 'srcIp', srcip, srcseed, srcmask, count) - self._update_ipv4_address( - self._get_stack_item(fg_id, PROTO_IPV4)[0], - 'dstIp', dstip, dstseed, dstmask, count) + if traffic_param['outer_l3']: + count = traffic_param['outer_l3']['count'] + srcip = traffic_param['outer_l3']['srcip'] + dstip = traffic_param['outer_l3']['dstip'] + srcseed = traffic_param['outer_l3']['srcseed'] + dstseed = traffic_param['outer_l3']['dstseed'] + srcmask = traffic_param['outer_l3']['srcmask'] \ + or ipaddress.IPV4LENGTH + dstmask = traffic_param['outer_l3']['dstmask'] \ + or ipaddress.IPV4LENGTH + if srcip: + self._update_ipv4_address( + self._get_stack_item(fg_id, PROTO_IPV4)[0], + 'srcIp', str(srcip), srcseed, srcmask, count) + if dstip: + self._update_ipv4_address( + self._get_stack_item(fg_id, PROTO_IPV4)[0], + 'dstIp', str(dstip), dstseed, dstmask, count) def update_l4(self, traffic): """Update the L4 headers @@ -520,7 +581,10 @@ class IxNextgen(object): # pragma: no cover if not self._get_config_element_by_flow_group_name(fg_id): raise exceptions.IxNetworkFlowNotPresent(flow_group=fg_id) - proto = traffic_param['outer_l3']['proto'] + proto = traffic_param['outer_l3'].get('proto') + if not (proto and traffic_param['outer_l4']): + continue + if proto not in SUPPORTED_PROTO: raise exceptions.IXIAUnsupportedProtocol(protocol=proto) @@ -533,12 +597,15 @@ class IxNextgen(object): # pragma: no cover dstport = traffic_param['outer_l4']['dstport'] dstmask = traffic_param['outer_l4']['dstportmask'] - if proto in SUPPORTED_PROTO: - self._update_udp_port(self._get_stack_item(fg_id, proto)[0], - 'srcPort', srcport, seed, srcmask, count) - - self._update_udp_port(self._get_stack_item(fg_id, proto)[0], - 'dstPort', dstport, seed, dstmask, count) + if proto == PROTO_UDP: + if srcport: + self._update_udp_port( + self._get_stack_item(fg_id, proto)[0], + 'srcPort', srcport, seed, srcmask, count) + if dstport: + self._update_udp_port( + self._get_stack_item(fg_id, proto)[0], + 'dstPort', dstport, seed, dstmask, count) def _update_udp_port(self, descriptor, field, value, seed=1, mask=0, count=1): @@ -572,6 +639,39 @@ class IxNextgen(object): # pragma: no cover 'getColumnValues', view_obj, data_ixia) for data_yardstick, data_ixia in name_map.items()} + def _set_egress_flow_tracking(self, encapsulation, offset): + """Set egress flow tracking options + + :param encapsulation: encapsulation type + :type encapsulation: str, e.g. 'Ethernet' + :param offset: offset type + :type offset: str, e.g. 'IPv4 TOS Precedence (3 bits)' + """ + traffic_item = self.ixnet.getList(self.ixnet.getRoot() + '/traffic', + 'trafficItem')[0] + # Enable Egress Tracking + self.ixnet.setAttribute(traffic_item, '-egressEnabled', True) + self.ixnet.commit() + + # Set encapsulation type + enc_obj = self.ixnet.getList(traffic_item, 'egressTracking')[0] + self.ixnet.setAttribute(enc_obj, '-encapsulation', encapsulation) + + # Set offset + self.ixnet.setAttribute(enc_obj, '-offset', offset) + self.ixnet.commit() + + def _set_flow_tracking(self, track_by): + """Set flow tracking options + + :param track_by: list of tracking fields + :type track_by: list, e.g. ['vlanVlanId0','ipv4Precedence0'] + """ + traffic_item = self.ixnet.getList(self.ixnet.getRoot() + '/traffic', + 'trafficItem')[0] + self.ixnet.setAttribute(traffic_item + '/tracking', '-trackBy', track_by) + self.ixnet.commit() + def get_statistics(self): """Retrieve port and flow statistics @@ -589,6 +689,12 @@ class IxNextgen(object): # pragma: no cover self.LATENCY_NAME_MAP)) return stats + def start_protocols(self): + self.ixnet.execute('startAllProtocols') + + def stop_protocols(self): + self.ixnet.execute('stopAllProtocols') + def start_traffic(self): """Start the traffic injection in the traffic item @@ -771,3 +877,29 @@ class IxNextgen(object): # pragma: no cover self.ixnet.commit() return obj + + def add_bgp(self, ipv4, dut_ip, local_as, bgp_type=None): + """Add BGP protocol""" + log.debug("add_bgp: ipv4='%s', dut_ip='%s', local_as='%s'", ipv4, + dut_ip, local_as) + obj = self.ixnet.add(ipv4, 'bgpIpv4Peer') + self.ixnet.commit() + + # Set DUT IP address + dut_ip_addr = self.ixnet.getAttribute(obj, '-dutIp') + self.ixnet.setAttribute(dut_ip_addr + '/singleValue', + '-value', dut_ip) + + # Set local AS number + local_as_number = self.ixnet.getAttribute(obj, '-localAs2Bytes') + self.ixnet.setAttribute(local_as_number + '/singleValue', + '-value', local_as) + + if bgp_type: + # Set BGP type. If not specified, default value is using. + # Default type is "internal" + bgp_type_field = self.ixnet.getAttribute(obj, '-type') + self.ixnet.setAttribute(bgp_type_field + '/singleValue', + '-value', bgp_type) + self.ixnet.commit() + return obj diff --git a/yardstick/network_services/traffic_profile/base.py b/yardstick/network_services/traffic_profile/base.py index 4fbceea9b..ea3f17874 100644 --- a/yardstick/network_services/traffic_profile/base.py +++ b/yardstick/network_services/traffic_profile/base.py @@ -97,6 +97,9 @@ class TrafficProfile(object): self.params = tp_config self.config = TrafficProfileConfig(tp_config) + def is_ended(self): + return False + def execute_traffic(self, traffic_generator, **kawrgs): """ This methods defines the behavior of the traffic generator. It will be called in a loop until the traffic generator exits. diff --git a/yardstick/network_services/traffic_profile/http.py b/yardstick/network_services/traffic_profile/http.py index 2d00fb849..31ab17ef7 100644 --- a/yardstick/network_services/traffic_profile/http.py +++ b/yardstick/network_services/traffic_profile/http.py @@ -24,6 +24,10 @@ class TrafficProfileGenericHTTP(TrafficProfile): def __init__(self, TrafficProfile): super(TrafficProfileGenericHTTP, self).__init__(TrafficProfile) + def get_links_param(self): + return {k: v for k, v in self.params.items() if + "uplink" in k or "downlink" in k} + def execute(self, traffic_generator): ''' send run traffic for a selected traffic generator''' pass diff --git a/yardstick/network_services/traffic_profile/http_ixload.py b/yardstick/network_services/traffic_profile/http_ixload.py index 39ee16b42..9210f3c6d 100644 --- a/yardstick/network_services/traffic_profile/http_ixload.py +++ b/yardstick/network_services/traffic_profile/http_ixload.py @@ -114,8 +114,10 @@ class IXLOADHttpTest(object): self.chassis = None self.card = None self.ports_to_reassign = None + self.links_param = None self.test_input = jsonutils.loads(test_input) self.parse_run_test() + self.test = None @staticmethod def format_ports_for_reassignment(ports): @@ -179,6 +181,90 @@ class IXLOADHttpTest(object): LOG.error('Error: IxLoad config file not found: %s', config_file) raise + def update_network_address(self, net_traffic, address, gateway, prefix): + """Update ip address and gateway for net_traffic object + + This function update field which configure source addresses for + traffic which is described by net_traffic object. + Do not return anything + + :param net_traffic: (IxLoadObjectProxy) proxy obj to tcl net_traffic object + :param address: (str) Ipv4 range start address + :param gateway: (str) Ipv4 address of gateway + :param prefix: (int) subnet prefix + :return: + """ + try: + ethernet = net_traffic.network.getL1Plugin() + ix_net_l2_ethernet_plugin = ethernet.childrenList[0] + ix_net_ip_v4_v6_plugin = ix_net_l2_ethernet_plugin.childrenList[0] + ix_net_ip_v4_v6_range = ix_net_ip_v4_v6_plugin.rangeList[0] + + ix_net_ip_v4_v6_range.config( + prefix=prefix, + ipAddress=address, + gatewayAddress=gateway) + except Exception: + raise exceptions.InvalidRxfFile + + def update_network_mac_address(self, net_traffic, mac): + """Update MACaddress for net_traffic object + + This function update field which configure MACaddresses for + traffic which is described by net_traffic object. + If mac == "auto" then will be configured auto generated mac + Do not return anything. + + :param net_traffic: (IxLoadObjectProxy) proxy obj to tcl net_traffic object + :param mac: (str) MAC + :return: + """ + try: + ethernet = net_traffic.network.getL1Plugin() + ix_net_l2_ethernet_plugin = ethernet.childrenList[0] + ix_net_ip_v4_v6_plugin = ix_net_l2_ethernet_plugin.childrenList[0] + ix_net_ip_v4_v6_range = ix_net_ip_v4_v6_plugin.rangeList[0] + + if str(mac).lower() == "auto": + ix_net_ip_v4_v6_range.config(autoMacGeneration=True) + else: + ix_net_ip_v4_v6_range.config(autoMacGeneration=False) + mac_range = ix_net_ip_v4_v6_range.getLowerRelatedRange( + "MacRange") + mac_range.config(mac=mac) + except Exception: + raise exceptions.InvalidRxfFile + + def update_network_param(self, net_traffic, param): + """Update net_traffic by parameters specified in param""" + + self.update_network_address(net_traffic, param["address"], + param["gateway"], param["subnet_prefix"]) + + self.update_network_mac_address(net_traffic, param["mac"]) + + def update_config(self): + """Update some fields by parameters from traffic profile""" + + net_traffics = {} + # self.test.communityList is a IxLoadObjectProxy to some tcl object + # which contain all net_traffic objects in scenario. + # net_traffic item has a name in format "activity_name@item_name" + try: + for item in self.test.communityList: + net_traffics[item.name.split('@')[1]] = item + except Exception: # pylint: disable=broad-except + pass + + for name, net_traffic in net_traffics.items(): + try: + param = self.links_param[name] + except KeyError: + LOG.debug('There is no param for net_traffic %s', name) + continue + + self.update_network_param(net_traffic, param["ip"]) + def start_http_test(self): self.ix_load = IxLoad() @@ -205,16 +291,18 @@ class IXLOADHttpTest(object): # Get the first test on the testList test_name = repository.testList[0].cget("name") - test = repository.testList.getItem(test_name) + self.test = repository.testList.getItem(test_name) self.set_results_dir(test_controller, self.results_on_windows) - test.config(statsRequired=1, enableResetPorts=1, csvInterval=2, - enableForceOwnership=True) + self.test.config(statsRequired=1, enableResetPorts=1, csvInterval=2, + enableForceOwnership=True) + + self.update_config() # ---- Remap ports ---- try: - self.reassign_ports(test, repository, self.ports_to_reassign) + self.reassign_ports(self.test, repository, self.ports_to_reassign) except Exception: # pylint: disable=broad-except LOG.exception("Exception occurred during reassign_ports") @@ -254,7 +342,7 @@ class IXLOADHttpTest(object): self.stat_utils.StartCollector(self.IxL_StatCollectorCommand) - test_controller.run(test) + test_controller.run(self.test) self.ix_load.waitForTestFinish() test_controller.releaseConfigWaitFinish() @@ -266,7 +354,7 @@ class IXLOADHttpTest(object): test_controller.generateReport(detailedReport=1, format="PDF;HTML") test_controller.releaseConfigWaitFinish() - self.ix_load.delete(test) + self.ix_load.delete(self.test) self.ix_load.delete(test_controller) self.ix_load.delete(logger) self.ix_load.delete(log_engine) @@ -304,6 +392,9 @@ class IXLOADHttpTest(object): LOG.debug("Ports to be reassigned: %s", self.ports_to_reassign) + self.links_param = self.test_input["links_param"] + LOG.debug("Links param to be applied: %s", self.links_param) + def main(args): # Get the args from cmdline and parse and run the test diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py index 44bf2eafc..0b7a78c2c 100644 --- a/yardstick/network_services/traffic_profile/ixia_rfc2544.py +++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py @@ -28,6 +28,8 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): DOWNLINK = 'downlink' DROP_PERCENT_ROUND = 6 RATE_ROUND = 5 + STATUS_SUCCESS = "Success" + STATUS_FAIL = "Failure" def __init__(self, yaml_data): super(IXIARFC2544Profile, self).__init__(yaml_data) @@ -56,68 +58,83 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): if not traffickey.startswith((self.UPLINK, self.DOWNLINK)): continue + # values should be single-item dict, so just grab the first item try: - # values should be single-item dict, so just grab the first item - try: - key, value = next(iter(values.items())) - except StopIteration: - result[traffickey] = {} - continue - - port_id = value.get('id', 1) - port_index = port_id - 1 - - if value.get('outer_l3v4'): - ip = value['outer_l3v4'] - src_key, dst_key = 'srcip4', 'dstip4' - else: - ip = value['outer_l3v6'] - src_key, dst_key = 'srcip6', 'dstip6' - - srcip, srcmask = self._get_ip_and_mask(ip[src_key]) - dstip, dstmask = self._get_ip_and_mask(ip[dst_key]) - - outer_l4 = value.get('outer_l4') - src_port, src_port_mask = self._get_fixed_and_mask(outer_l4['srcport']) - dst_port, dst_port_mask = self._get_fixed_and_mask(outer_l4['dstport']) - result[traffickey] = { - 'bidir': False, - 'id': port_id, - 'rate': self.rate, - 'rate_unit': self.rate_unit, - 'outer_l2': { - 'framesize': value['outer_l2']['framesize'], - 'framesPerSecond': True, - 'QinQ': value['outer_l2'].get('QinQ'), - 'srcmac': mac['src_mac_{}'.format(port_index)], - 'dstmac': mac['dst_mac_{}'.format(port_index)], - }, - 'outer_l3': { - 'count': ip['count'], - 'dscp': ip['dscp'], - 'ttl': ip['ttl'], - 'srcseed': ip.get('srcseed', 1), - 'dstseed': ip.get('dstseed', 1), - 'srcip': srcip, - 'dstip': dstip, - 'srcmask': srcmask, - 'dstmask': dstmask, - 'type': key, - 'proto': ip['proto'], - }, - 'outer_l4': { - 'srcport': src_port, - 'dstport': dst_port, - 'srcportmask': src_port_mask, - 'dstportmask': dst_port_mask, - 'count': outer_l4['count'], - 'seed': outer_l4.get('seed', 1) - } - - } - except KeyError: + key, value = next(iter(values.items())) + except StopIteration: + result[traffickey] = {} continue + port_id = value.get('id', 1) + port_index = port_id - 1 + + result[traffickey] = { + 'bidir': False, + 'id': port_id, + 'rate': self.rate, + 'rate_unit': self.rate_unit, + 'outer_l2': {}, + 'outer_l3': {}, + 'outer_l4': {}, + } + + outer_l2 = value.get('outer_l2') + if outer_l2: + result[traffickey]['outer_l2'].update({ + 'framesize': outer_l2.get('framesize'), + 'framesPerSecond': True, + 'QinQ': outer_l2.get('QinQ'), + 'srcmac': mac.get('src_mac_{}'.format(port_index)), + 'dstmac': mac.get('dst_mac_{}'.format(port_index)), + }) + + if value.get('outer_l3v4'): + outer_l3 = value['outer_l3v4'] + src_key, dst_key = 'srcip4', 'dstip4' + else: + outer_l3 = value.get('outer_l3v6') + src_key, dst_key = 'srcip6', 'dstip6' + if outer_l3: + srcip = srcmask = dstip = dstmask = None + if outer_l3.get(src_key): + srcip, srcmask = self._get_ip_and_mask(outer_l3[src_key]) + if outer_l3.get(dst_key): + dstip, dstmask = self._get_ip_and_mask(outer_l3[dst_key]) + + result[traffickey]['outer_l3'].update({ + 'count': outer_l3.get('count', 1), + 'dscp': outer_l3.get('dscp'), + 'ttl': outer_l3.get('ttl'), + 'srcseed': outer_l3.get('srcseed', 1), + 'dstseed': outer_l3.get('dstseed', 1), + 'srcip': srcip, + 'dstip': dstip, + 'srcmask': srcmask, + 'dstmask': dstmask, + 'type': key, + 'proto': outer_l3.get('proto'), + }) + + outer_l4 = value.get('outer_l4') + if outer_l4: + src_port = src_port_mask = dst_port = dst_port_mask = None + if outer_l4.get('srcport'): + src_port, src_port_mask = ( + self._get_fixed_and_mask(outer_l4['srcport'])) + + if outer_l4.get('dstport'): + dst_port, dst_port_mask = ( + self._get_fixed_and_mask(outer_l4['dstport'])) + + result[traffickey]['outer_l4'].update({ + 'srcport': src_port, + 'dstport': dst_port, + 'srcportmask': src_port_mask, + 'dstportmask': dst_port_mask, + 'count': outer_l4.get('count', 1), + 'seed': outer_l4.get('seed', 1), + }) + return result def _ixia_traffic_generate(self, traffic, ixia_obj): @@ -159,7 +176,7 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): self._ixia_traffic_generate(traffic, ixia_obj) return first_run - def get_drop_percentage(self, samples, tol_min, tolerance, + def get_drop_percentage(self, samples, tol_min, tolerance, precision, first_run=False): completed = False drop_percent = 100 @@ -193,6 +210,10 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): else: completed = True + LOG.debug("tolerance=%s, tolerance_precision=%s drop_percent=%s " + "completed=%s", tolerance, precision, drop_percent, + completed) + latency_ns_avg = float( sum([samples[iface]['Store-Forward_Avg_latency_ns'] for iface in samples])) / num_ifaces @@ -203,6 +224,10 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): sum([samples[iface]['Store-Forward_Max_latency_ns'] for iface in samples])) / num_ifaces + samples['Status'] = self.STATUS_FAIL + if round(drop_percent, precision) <= tolerance: + samples['Status'] = self.STATUS_SUCCESS + samples['TxThroughput'] = tx_throughput samples['RxThroughput'] = rx_throughput samples['DropPercentage'] = drop_percent diff --git a/yardstick/network_services/traffic_profile/prox_binsearch.py b/yardstick/network_services/traffic_profile/prox_binsearch.py index 16a0411ec..f924cf419 100644 --- a/yardstick/network_services/traffic_profile/prox_binsearch.py +++ b/yardstick/network_services/traffic_profile/prox_binsearch.py @@ -66,6 +66,9 @@ class ProxBinSearchProfile(ProxProfile): yield test_value test_value = self.mid_point + def is_ended(self): + return self.done.is_set() + def run_test_with_pkt_size(self, traffic_gen, pkt_size, duration): """Run the test for a single packet size. @@ -93,7 +96,7 @@ class ProxBinSearchProfile(ProxProfile): # success, the binary search will complete on an integer multiple # of the precision, rather than on a fraction of it. - theor_max_thruput = 0 + theor_max_thruput = 0.0 result_samples = {} @@ -195,9 +198,9 @@ class ProxBinSearchProfile(ProxProfile): LOG.info( ">>>##>> Result Reached PktSize %s Theor_Max_Thruput %s Actual_throughput %s", - pkt_size, theor_max_thruput, result_samples.get("RxThroughput", 0)) + pkt_size, theor_max_thruput, result_samples.get("RxThroughput", 0.0)) result_samples["Status"] = STATUS_RESULT result_samples["Next_Step"] = "" - result_samples["Actual_throughput"] = result_samples.get("RxThroughput", 0) + result_samples["Actual_throughput"] = result_samples.get("RxThroughput", 0.0) result_samples["theor_max_throughput"] = theor_max_thruput self.queue.put(result_samples) diff --git a/yardstick/network_services/traffic_profile/prox_profile.py b/yardstick/network_services/traffic_profile/prox_profile.py index 343ef1da2..de4b3f9a0 100644 --- a/yardstick/network_services/traffic_profile/prox_profile.py +++ b/yardstick/network_services/traffic_profile/prox_profile.py @@ -16,6 +16,7 @@ from __future__ import absolute_import import logging +import multiprocessing from yardstick.network_services.traffic_profile.base import TrafficProfile from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxProfileHelper @@ -56,7 +57,7 @@ class ProxProfile(TrafficProfile): def __init__(self, tp_config): super(ProxProfile, self).__init__(tp_config) self.queue = None - self.done = False + self.done = multiprocessing.Event() self.results = [] # TODO: get init values from tp_config @@ -116,7 +117,7 @@ class ProxProfile(TrafficProfile): try: pkt_size = next(self.pkt_size_iterator) except StopIteration: - self.done = True + self.done.set() return # Adjust packet size upwards if it's less than the minimum diff --git a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py index 3241719e8..321c05779 100644 --- a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py +++ b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py @@ -984,7 +984,7 @@ class ProxResourceHelper(ClientResourceHelper): def _run_traffic_once(self, traffic_profile): traffic_profile.execute_traffic(self) - if traffic_profile.done: + if traffic_profile.done.is_set(): self._queue.put({'done': True}) LOG.debug("tg_prox done") self._terminated.value = 1 diff --git a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py index a09f2a7a9..21719cbf0 100644 --- a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py @@ -13,6 +13,7 @@ # limitations under the License. import logging +import decimal from multiprocessing import Queue, Value, Process import os import posixpath @@ -499,6 +500,7 @@ class Rfc2544ResourceHelper(object): self._rfc2544 = None self._tolerance_low = None self._tolerance_high = None + self._tolerance_precision = None @property def rfc2544(self): @@ -519,6 +521,12 @@ class Rfc2544ResourceHelper(object): return self._tolerance_high @property + def tolerance_precision(self): + if self._tolerance_precision is None: + self.get_rfc_tolerance() + return self._tolerance_precision + + @property def correlated_traffic(self): if self._correlated_traffic is None: self._correlated_traffic = \ @@ -537,9 +545,13 @@ class Rfc2544ResourceHelper(object): def get_rfc_tolerance(self): tolerance_str = self.get_rfc2544('allowed_drop_rate', self.DEFAULT_TOLERANCE) - tolerance_iter = iter(sorted(float(t.strip()) for t in tolerance_str.split('-'))) - self._tolerance_low = next(tolerance_iter) - self._tolerance_high = next(tolerance_iter, self.tolerance_low) + tolerance_iter = iter(sorted( + decimal.Decimal(t.strip()) for t in tolerance_str.split('-'))) + tolerance_low = next(tolerance_iter) + tolerance_high = next(tolerance_iter, tolerance_low) + self._tolerance_precision = abs(tolerance_high.as_tuple().exponent) + self._tolerance_high = float(tolerance_high) + self._tolerance_low = float(tolerance_low) class SampleVNFDeployHelper(object): diff --git a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py index e0fc47dbf..d25402740 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py @@ -20,9 +20,11 @@ import os import shutil import subprocess +from oslo_serialization import jsonutils + from yardstick.common import utils -from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen -from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper +from yardstick.network_services.vnf_generic.vnf import sample_vnf + LOG = logging.getLogger(__name__) @@ -43,7 +45,8 @@ IXLOAD_CONFIG_TEMPLATE = '''\ }, "remote_server": "%s", "result_dir": "%s", - "ixload_cfg": "C:/Results/%s" + "ixload_cfg": "C:/Results/%s", + "links_param": %s }''' IXLOAD_CMD = "{ixloadpy} {http_ixload} {args}" @@ -59,7 +62,7 @@ class ResourceDataHelper(list): } -class IxLoadResourceHelper(ClientResourceHelper): +class IxLoadResourceHelper(sample_vnf.ClientResourceHelper): RESULTS_MOUNT = "/mnt/Results" @@ -121,7 +124,7 @@ class IxLoadResourceHelper(ClientResourceHelper): LOG.debug(self.result[key]) -class IxLoadTrafficGen(SampleVNFTrafficGen): +class IxLoadTrafficGen(sample_vnf.SampleVNFTrafficGen): def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, resource_helper_type=None): @@ -132,6 +135,21 @@ class IxLoadTrafficGen(SampleVNFTrafficGen): name, vnfd, task_id, setup_env_helper_type, resource_helper_type) self._result = {} + def update_gateways(self, links): + for name in links: + try: + gateway = next(intf["virtual-interface"]["dst_ip"] for intf in + self.setup_helper.vnfd_helper["vdu"][0][ + "external-interface"] if + intf["virtual-interface"]["vld_id"] == name) + + links[name]["ip"]["gateway"] = gateway + except StopIteration: + LOG.debug("Cant find gateway for link %s", name) + links[name]["ip"]["gateway"] = "0.0.0.0" + + return links + def run_traffic(self, traffic_profile): ports = [] card = None @@ -143,11 +161,16 @@ class IxLoadTrafficGen(SampleVNFTrafficGen): for csv_file in glob.iglob(self.ssh_helper.join_bin_path('*.csv')): os.unlink(csv_file) + links_param = self.update_gateways( + traffic_profile.get_links_param()) + ixia_config = self.vnfd_helper.mgmt_interface["tg-config"] ixload_config = IXLOAD_CONFIG_TEMPLATE % ( ixia_config["ixchassis"], ports, card, self.vnfd_helper.mgmt_interface["ip"], self.ssh_helper.bin_path, - os.path.basename(self.resource_helper.resource_file_name)) + os.path.basename(self.resource_helper.resource_file_name), + jsonutils.dumps(links_param) + ) http_ixload_path = os.path.join(VNF_PATH, "../../traffic_profile") diff --git a/yardstick/network_services/vnf_generic/vnf/tg_landslide.py b/yardstick/network_services/vnf_generic/vnf/tg_landslide.py index a146b72ca..2fba89b22 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_landslide.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_landslide.py @@ -129,6 +129,17 @@ class LandslideTrafficGen(sample_vnf.SampleVNFTrafficGen): self.session_profile['reservePorts'] = 'true' self.session_profile['reservations'] = [reservation] + def _update_session_library_name(self, test_session): + """Update DMF library name in session profile""" + for _ts_group in test_session['tsGroups']: + for _tc in _ts_group['testCases']: + try: + for _mainflow in _tc['parameters']['Dmf']['mainflows']: + _mainflow['library'] = \ + self.vnfd_helper.mgmt_interface['user'] + except KeyError: + pass + @staticmethod def _update_session_tc_params(tc_options, testcase): for _param_key in tc_options: @@ -206,6 +217,8 @@ class LandslideTrafficGen(sample_vnf.SampleVNFTrafficGen): _testcase_idx].update( self._update_session_tc_params(tc_options, _testcase)) + self._update_session_library_name(self.session_profile) + class LandslideResourceHelper(sample_vnf.ClientResourceHelper): """Landslide TG helper class""" @@ -459,11 +472,14 @@ class LandslideResourceHelper(sample_vnf.ClientResourceHelper): self._terminated.value = 1 def create_dmf(self, dmf): - if isinstance(dmf, list): - for _dmf in dmf: - self._tcl.create_dmf(_dmf) - else: - self._tcl.create_dmf(dmf) + if isinstance(dmf, dict): + dmf = [dmf] + for _dmf in dmf: + # Update DMF library name in traffic profile + _dmf['dmf'].update( + {'library': self.vnfd_helper.mgmt_interface['user']}) + # Create DMF on Landslide server + self._tcl.create_dmf(_dmf) def delete_dmf(self, dmf): if isinstance(dmf, list): @@ -600,6 +616,13 @@ class LandslideResourceHelper(sample_vnf.ClientResourceHelper): def create_test_session(self, test_session): # Use tcl client to create session test_session['library'] = self._user_id + + # If no traffic duration set in test case, use predefined default value + # in session profile + test_session['duration'] = self.scenario_helper.all_options.get( + 'traffic_duration', + test_session['duration']) + LOG.debug("Creating session='%s'", test_session['name']) self._tcl.create_test_session(test_session) diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py index 94ab06980..89f8194c0 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py @@ -96,7 +96,10 @@ class IxiaResourceHelper(ClientResourceHelper): """Initialize the IXIA IxNetwork client and configure the server""" self.client.clear_config() self.client.assign_ports() - self.client.create_traffic_model() + vports = self.client.get_vports() + uplink_vports = vports[::2] + downlink_vports = vports[1::2] + self.client.create_traffic_model(uplink_vports, downlink_vports) def run_traffic(self, traffic_profile, *args): if self._terminated.value: @@ -104,6 +107,7 @@ class IxiaResourceHelper(ClientResourceHelper): min_tol = self.rfc_helper.tolerance_low max_tol = self.rfc_helper.tolerance_high + precision = self.rfc_helper.tolerance_precision default = "00:00:00:00:00:00" self._build_ports() @@ -131,7 +135,7 @@ class IxiaResourceHelper(ClientResourceHelper): traffic_profile.config.duration) completed, samples = traffic_profile.get_drop_percentage( - samples, min_tol, max_tol, first_run=first_run) + samples, min_tol, max_tol, precision, first_run=first_run) self._queue.put(samples) if completed: diff --git a/yardstick/tests/functional/common/test_packages.py b/yardstick/tests/functional/common/test_packages.py index 5dead4e55..14de46bcf 100644 --- a/yardstick/tests/functional/common/test_packages.py +++ b/yardstick/tests/functional/common/test_packages.py @@ -39,16 +39,21 @@ class PipPackagesTestCase(base.BaseFunctionalTestCase): utils.execute_command('sudo rm -rf %s' % self.TMP_FOLDER) def _remove_package(self, package): - os.system('%s pip uninstall %s -y' % (self.PYTHONPATH, package)) + os.system('%s python -m pip uninstall %s -y' % + (self.PYTHONPATH, package)) def _list_packages(self): pip_list_regex = re.compile( r"(?P<name>[\w\.-]+) \((?P<version>[\w\d_\.\-]+),*.*\)") + pip_list_regex_18 = re.compile( + r"(?P<name>[\w\.-]+)[\s]+(?P<version>[\w\d_\.\-]+),*.*") pkg_dict = {} - pkgs = utils.execute_command('pip list', + pkgs = utils.execute_command('python -m pip list', env={'PYTHONPATH': self.TMP_FOLDER}) for line in pkgs: match = pip_list_regex.match(line) + if not match: + match = pip_list_regex_18.match(line) if match and match.group('name'): pkg_dict[match.group('name')] = match.group('version') return pkg_dict diff --git a/yardstick/tests/unit/benchmark/runner/test_duration.py b/yardstick/tests/unit/benchmark/runner/test_duration.py index d4801ef2c..fa47e96bf 100644 --- a/yardstick/tests/unit/benchmark/runner/test_duration.py +++ b/yardstick/tests/unit/benchmark/runner/test_duration.py @@ -97,9 +97,9 @@ class DurationRunnerTest(unittest.TestCase): multiprocessing.Event(), mock.Mock()) self._assert_defaults__worker_run_setup_and_teardown() - self.assertGreater(self.benchmark.pre_run_wait_time.call_count, 2) - self.assertGreater(self.benchmark.my_method.call_count, 2) - self.assertGreater(self.benchmark.post_run_wait_time.call_count, 2) + self.assertGreater(self.benchmark.pre_run_wait_time.call_count, 0) + self.assertGreater(self.benchmark.my_method.call_count, 0) + self.assertGreater(self.benchmark.post_run_wait_time.call_count, 0) def test__worker_process_called_without_cfg(self): scenario_cfg = {'runner': {}} @@ -140,9 +140,9 @@ class DurationRunnerTest(unittest.TestCase): time.sleep(0.1) self._assert_defaults__worker_run_setup_and_teardown() - self.assertGreater(self.benchmark.pre_run_wait_time.call_count, 2) - self.assertGreater(self.benchmark.my_method.count, 103) - self.assertGreater(self.benchmark.post_run_wait_time.call_count, 2) + self.assertGreater(self.benchmark.pre_run_wait_time.call_count, 0) + self.assertGreater(self.benchmark.my_method.count, 1) + self.assertGreater(self.benchmark.post_run_wait_time.call_count, 0) count = 101 while not output_queue.empty(): @@ -181,9 +181,9 @@ class DurationRunnerTest(unittest.TestCase): time.sleep(0.1) self._assert_defaults__worker_run_setup_and_teardown() - self.assertGreater(self.benchmark.pre_run_wait_time.call_count, 2) - self.assertGreater(self.benchmark.my_method.count, 103) - self.assertGreater(self.benchmark.post_run_wait_time.call_count, 2) + self.assertGreater(self.benchmark.pre_run_wait_time.call_count, 0) + self.assertGreater(self.benchmark.my_method.count, 1) + self.assertGreater(self.benchmark.post_run_wait_time.call_count, 0) count = 0 while not queue.empty(): diff --git a/yardstick/tests/unit/benchmark/runner/test_proxduration.py b/yardstick/tests/unit/benchmark/runner/test_proxduration.py index 3299c5b05..056195fd3 100644 --- a/yardstick/tests/unit/benchmark/runner/test_proxduration.py +++ b/yardstick/tests/unit/benchmark/runner/test_proxduration.py @@ -97,7 +97,7 @@ class ProxDurationRunnerTest(unittest.TestCase): {}, multiprocessing.Event(), mock.Mock()) self._assert_defaults__worker_run_setup_and_teardown() - self.assertGreater(self.benchmark.my_method.call_count, 2) + self.assertGreater(self.benchmark.my_method.call_count, 0) def test__worker_process_called_without_cfg(self): scenario_cfg = {'runner': {}} diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py index 6bf2f2c2f..90248d1bf 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py @@ -629,7 +629,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): @mock.patch.object(vnfdgen, 'generate_vnfd') def test__fill_traffic_profile(self, mock_generate, mock_tprofile_get): fake_tprofile = mock.Mock() - fake_vnfd = mock.Mock() + fake_vnfd = mock.MagicMock() with mock.patch.object(self.s, '_get_traffic_profile', return_value=fake_tprofile) as mock_get_tp: mock_generate.return_value = fake_vnfd @@ -646,6 +646,22 @@ class TestNetworkServiceTestCase(unittest.TestCase): ) mock_tprofile_get.assert_called_once_with(fake_vnfd) + @mock.patch.object(base.TrafficProfile, 'get') + @mock.patch.object(vnfdgen, 'generate_vnfd') + def test__fill_traffic_profile2(self, mock_generate, mock_tprofile_get): + fake_tprofile = mock.Mock() + fake_vnfd = {} + with mock.patch.object(self.s, '_get_traffic_profile', + return_value=fake_tprofile) as mock_get_tp: + mock_generate.return_value = fake_vnfd + + self.s.scenario_cfg["options"] = {"traffic_config": {"duration": 99899}} + self.s._fill_traffic_profile() + mock_get_tp.assert_called_once() + self.assertIn("traffic_profile", fake_vnfd) + self.assertIn("duration", fake_vnfd["traffic_profile"]) + self.assertEqual(99899, fake_vnfd["traffic_profile"]["duration"]) + @mock.patch.object(utils, 'open_relative_file') def test__get_topology(self, mock_open_path): self.s.scenario_cfg['topology'] = 'fake_topology' diff --git a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py index 4e3199a83..c80cbbe77 100644 --- a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py +++ b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py @@ -334,6 +334,21 @@ class TestIxNextgen(unittest.TestCase): self.ixnet_gen.ixnet.setMultiAttribute.assert_not_called() + def test_add_bgp(self): + self.ixnet_gen.ixnet.add.return_value = 'obj' + self.ixnet_gen.ixnet.getAttribute.return_value = 'attr' + self.ixnet_gen.add_bgp(ipv4='ipv4 1', + dut_ip='10.0.0.1', + local_as=65000, + bgp_type='external') + self.ixnet_gen.ixnet.add.assert_called_once_with('ipv4 1', 'bgpIpv4Peer') + self.ixnet_gen.ixnet.setAttribute.assert_any_call( + 'attr/singleValue', '-value', '10.0.0.1') + self.ixnet_gen.ixnet.setAttribute.assert_any_call( + 'attr/singleValue', '-value', 65000) + self.ixnet_gen.ixnet.setAttribute.assert_any_call( + 'attr/singleValue', '-value', 'external') + @mock.patch.object(IxNetwork, 'IxNet') def test_connect(self, mock_ixnet): mock_ixnet.return_value = self.ixnet @@ -421,17 +436,24 @@ class TestIxNextgen(unittest.TestCase): '-trackBy', 'trafficGroupId0') def test__create_flow_groups(self): + uplink_endpoints = ['up_endp1', 'up_endp2'] + downlink_endpoints = ['down_endp1', 'down_endp2'] self.ixnet_gen.ixnet.getList.side_effect = [['traffic_item'], ['1', '2']] - self.ixnet_gen.ixnet.add.side_effect = ['endp1', 'endp2'] - self.ixnet_gen._create_flow_groups() + self.ixnet_gen.ixnet.add.side_effect = ['endp1', 'endp2', 'endp3', + 'endp4'] + self.ixnet_gen._create_flow_groups(uplink_endpoints, downlink_endpoints) self.ixnet_gen.ixnet.add.assert_has_calls([ mock.call('traffic_item', 'endpointSet'), mock.call('traffic_item', 'endpointSet')]) self.ixnet_gen.ixnet.setMultiAttribute.assert_has_calls([ - mock.call('endp1', '-name', '1', '-sources', ['1/protocols'], - '-destinations', ['2/protocols']), - mock.call('endp2', '-name', '2', '-sources', ['2/protocols'], - '-destinations', ['1/protocols'])]) + mock.call('endp1', '-name', '1', '-sources', ['up_endp1'], + '-destinations', ['down_endp1']), + mock.call('endp2', '-name', '2', '-sources', ['down_endp1'], + '-destinations', ['up_endp1']), + mock.call('endp3', '-name', '3', '-sources', ['up_endp2'], + '-destinations', ['down_endp2']), + mock.call('endp4', '-name', '4', '-sources', ['down_endp2'], + '-destinations', ['up_endp2'])]) def test__append_protocol_to_stack(self): @@ -461,12 +483,31 @@ class TestIxNextgen(unittest.TestCase): def test_create_traffic_model(self, mock__setup_config_elements, mock__create_flow_groups, mock__create_traffic_item): - - self.ixnet_gen.create_traffic_model() - mock__create_traffic_item.assert_called_once() - mock__create_flow_groups.assert_called_once() + uplink_ports = ['port1', 'port3'] + downlink_ports = ['port2', 'port4'] + uplink_endpoints = ['port1/protocols', 'port3/protocols'] + downlink_endpoints = ['port2/protocols', 'port4/protocols'] + self.ixnet_gen.create_traffic_model(uplink_ports, downlink_ports) + mock__create_traffic_item.assert_called_once_with('raw') + mock__create_flow_groups.assert_called_once_with(uplink_endpoints, + downlink_endpoints) mock__setup_config_elements.assert_called_once() + @mock.patch.object(ixnet_api.IxNextgen, '_create_traffic_item') + @mock.patch.object(ixnet_api.IxNextgen, '_create_flow_groups') + @mock.patch.object(ixnet_api.IxNextgen, '_setup_config_elements') + def test_create_ipv4_traffic_model(self, mock__setup_config_elements, + mock__create_flow_groups, + mock__create_traffic_item): + uplink_topologies = ['up1', 'up3'] + downlink_topologies = ['down2', 'down4'] + self.ixnet_gen.create_ipv4_traffic_model(uplink_topologies, + downlink_topologies) + mock__create_traffic_item.assert_called_once_with('ipv4') + mock__create_flow_groups.assert_called_once_with(uplink_topologies, + downlink_topologies) + mock__setup_config_elements.assert_called_once_with(False) + def test__update_frame_mac(self): with mock.patch.object(self.ixnet_gen, '_get_field_in_stack_item') as \ mock_get_field: @@ -551,6 +592,26 @@ class TestIxNextgen(unittest.TestCase): mock.call(port_statistics, self.ixnet_gen.PORT_STATS_NAME_MAP), mock.call(flow_statistics, self.ixnet_gen.LATENCY_NAME_MAP)]) + def test__set_flow_tracking(self): + self.ixnet_gen._ixnet.getList.return_value = ['traffic_item'] + self.ixnet_gen._set_flow_tracking(track_by=['vlanVlanId0']) + self.ixnet_gen.ixnet.setAttribute.assert_called_once_with( + 'traffic_item/tracking', '-trackBy', ['vlanVlanId0']) + self.assertEqual(self.ixnet.commit.call_count, 1) + + def test__set_egress_flow_tracking(self): + self.ixnet_gen._ixnet.getList.side_effect = [['traffic_item'], + ['encapsulation']] + self.ixnet_gen._set_egress_flow_tracking(encapsulation='Ethernet', + offset='IPv4 TOS Precedence') + self.ixnet_gen.ixnet.setAttribute.assert_any_call( + 'traffic_item', '-egressEnabled', True) + self.ixnet_gen.ixnet.setAttribute.assert_any_call( + 'encapsulation', '-encapsulation', 'Ethernet') + self.ixnet_gen.ixnet.setAttribute.assert_any_call( + 'encapsulation', '-offset', 'IPv4 TOS Precedence') + self.assertEqual(self.ixnet.commit.call_count, 2) + def test__update_ipv4_address(self): with mock.patch.object(self.ixnet_gen, '_get_field_in_stack_item', return_value='field_desc'): @@ -617,6 +678,9 @@ class TestIxNextgen(unittest.TestCase): 'outer_l3': { 'proto': 'unsupported', }, + 'outer_l4': { + 'seed': 1 + } }, } with mock.patch.object(self.ixnet_gen, @@ -672,3 +736,34 @@ class TestIxNextgen(unittest.TestCase): self.assertIsNone(result) self.ixnet.getList.assert_called_once() self.assertEqual(3, self.ixnet_gen._ixnet.execute.call_count) + + def test__get_protocol_status(self): + self.ixnet.getAttribute.return_value = ['up'] + self.ixnet_gen._get_protocol_status('ipv4') + self.ixnet.getAttribute.assert_called_once_with('ipv4', + '-sessionStatus') + + @mock.patch.object(ixnet_api.IxNextgen, '_get_protocol_status') + def test_is_protocols_running(self, mock_ixnextgen_get_protocol_status): + mock_ixnextgen_get_protocol_status.return_value = 'up' + result = self.ixnet_gen.is_protocols_running(['ethernet', 'ipv4']) + self.assertTrue(result) + + @mock.patch.object(ixnet_api.IxNextgen, '_get_protocol_status') + def test_is_protocols_stopped(self, mock_ixnextgen_get_protocol_status): + mock_ixnextgen_get_protocol_status.return_value = 'down' + result = self.ixnet_gen.is_protocols_running(['ethernet', 'ipv4']) + self.assertFalse(result) + + def test_start_protocols(self): + self.ixnet_gen.start_protocols() + self.ixnet.execute.assert_called_once_with('startAllProtocols') + + def test_stop_protocols(self): + self.ixnet_gen.stop_protocols() + self.ixnet.execute.assert_called_once_with('stopAllProtocols') + + def test_get_vports(self): + self.ixnet_gen._ixnet.getRoot.return_value = 'root' + self.ixnet_gen.get_vports() + self.ixnet.getList.assert_called_once_with('root', 'vport') diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_http.py b/yardstick/tests/unit/network_services/traffic_profile/test_http.py index d44fab2b5..874ec37d4 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_http.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_http.py @@ -19,13 +19,21 @@ from yardstick.network_services.traffic_profile import http class TestTrafficProfileGenericHTTP(unittest.TestCase): - TP_CONFIG = {'traffic_profile': {'duration': 10}} + TP_CONFIG = {'traffic_profile': {'duration': 10}, + "uplink_0": {}, "downlink_0": {}} def test___init__(self): tp_generic_http = http.TrafficProfileGenericHTTP( self.TP_CONFIG) self.assertIsNotNone(tp_generic_http) + def test_get_links_param(self): + tp_generic_http = http.TrafficProfileGenericHTTP( + self.TP_CONFIG) + + links = tp_generic_http.get_links_param() + self.assertEqual({"uplink_0": {}, "downlink_0": {}}, links) + def test_execute(self): tp_generic_http = http.TrafficProfileGenericHTTP( self.TP_CONFIG) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_http_ixload.py b/yardstick/tests/unit/network_services/traffic_profile/test_http_ixload.py index 57de6602d..1adab48bc 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_http_ixload.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_http_ixload.py @@ -17,6 +17,7 @@ import mock from oslo_serialization import jsonutils +from yardstick.common import exceptions from yardstick.network_services.traffic_profile import http_ixload from yardstick.network_services.traffic_profile.http_ixload import \ join_non_strings, validate_non_string_sequence @@ -45,6 +46,26 @@ class TestJoinNonStrings(unittest.TestCase): class TestIxLoadTrafficGen(unittest.TestCase): + def setUp(self): + ports = [1, 2, 3] + self.test_input = { + "remote_server": "REMOTE_SERVER", + "ixload_cfg": "IXLOAD_CFG", + "result_dir": "RESULT_DIR", + "ixia_chassis": "IXIA_CHASSIS", + "IXIA": { + "card": "CARD", + "ports": ports, + }, + 'links_param': { + "uplink_0": { + "ip": {"address": "address", + "gateway": "gateway", + "subnet_prefix": "subnet_prefix", + "mac": "mac" + }}} + } + def test_parse_run_test(self): ports = [1, 2, 3] test_input = { @@ -56,6 +77,7 @@ class TestIxLoadTrafficGen(unittest.TestCase): "card": "CARD", "ports": ports, }, + 'links_param': {} } j = jsonutils.dump_as_bytes(test_input) ixload = http_ixload.IXLOADHttpTest(j) @@ -66,6 +88,7 @@ class TestIxLoadTrafficGen(unittest.TestCase): ["IXIA_CHASSIS", "CARD", 2], ["IXIA_CHASSIS", "CARD", 3], ]) + self.assertEqual({}, ixload.links_param) def test_format_ports_for_reassignment(self): ports = [ @@ -91,6 +114,7 @@ class TestIxLoadTrafficGen(unittest.TestCase): "card": "CARD", "ports": ports, }, + 'links_param': {} } j = jsonutils.dump_as_bytes(test_input) ixload = http_ixload.IXLOADHttpTest(j) @@ -112,6 +136,7 @@ class TestIxLoadTrafficGen(unittest.TestCase): "card": "CARD", "ports": ports, }, + 'links_param': {} } j = jsonutils.dump_as_bytes(test_input) ixload = http_ixload.IXLOADHttpTest(j) @@ -160,6 +185,7 @@ class TestIxLoadTrafficGen(unittest.TestCase): "card": "CARD", "ports": ports, }, + 'links_param': {} } j = jsonutils.dump_as_bytes(test_input) ixload = http_ixload.IXLOADHttpTest(j) @@ -178,6 +204,7 @@ class TestIxLoadTrafficGen(unittest.TestCase): "card": "CARD", "ports": ports, }, + 'links_param': {} } j = jsonutils.dump_as_bytes(test_input) ixload = http_ixload.IXLOADHttpTest(j) @@ -198,6 +225,7 @@ class TestIxLoadTrafficGen(unittest.TestCase): "card": "CARD", "ports": ports, }, + 'links_param': {} } j = jsonutils.dump_as_bytes(test_input) @@ -211,6 +239,105 @@ class TestIxLoadTrafficGen(unittest.TestCase): with self.assertRaises(RuntimeError): ixload.start_http_test() + def test_update_config(self): + net_taraffic_0 = mock.Mock() + net_taraffic_0.name = "HTTP client@uplink_0" + net_taraffic_1 = mock.Mock() + net_taraffic_1.name = "HTTP client@uplink_1" + + community_list = [net_taraffic_0, net_taraffic_1, Exception] + ixload = http_ixload.IXLOADHttpTest( + jsonutils.dump_as_bytes(self.test_input)) + + ixload.links_param = {"uplink_0": {"ip": {}}} + + ixload.test = mock.Mock() + ixload.test.communityList = community_list + + ixload.update_network_param = mock.Mock() + + ixload.update_config() + + ixload.update_network_param.assert_called_once_with(net_taraffic_0, {}) + + def test_update_network_mac_address(self): + ethernet = mock.MagicMock() + net_traffic = mock.Mock() + net_traffic.network.getL1Plugin.return_value = ethernet + + ixload = http_ixload.IXLOADHttpTest( + jsonutils.dump_as_bytes(self.test_input)) + + ix_net_l2_ethernet_plugin = ethernet.childrenList[0] + ix_net_ip_v4_v6_plugin = ix_net_l2_ethernet_plugin.childrenList[0] + ix_net_ip_v4_v6_range = ix_net_ip_v4_v6_plugin.rangeList[0] + + ixload.update_network_mac_address(net_traffic, "auto") + ix_net_ip_v4_v6_range.config.assert_called_once_with( + autoMacGeneration=True) + + ixload.update_network_mac_address(net_traffic, "00:00:00:00:00:01") + ix_net_ip_v4_v6_range.config.assert_called_with( + autoMacGeneration=False) + mac_range = ix_net_ip_v4_v6_range.getLowerRelatedRange("MacRange") + mac_range.config.assert_called_once_with(mac="00:00:00:00:00:01") + + net_traffic.network.getL1Plugin.return_value = Exception + + with self.assertRaises(exceptions.InvalidRxfFile): + ixload.update_network_mac_address(net_traffic, "auto") + + def test_update_network_address(self): + ethernet = mock.MagicMock() + net_traffic = mock.Mock() + net_traffic.network.getL1Plugin.return_value = ethernet + + ixload = http_ixload.IXLOADHttpTest( + jsonutils.dump_as_bytes(self.test_input)) + + ix_net_l2_ethernet_plugin = ethernet.childrenList[0] + ix_net_ip_v4_v6_plugin = ix_net_l2_ethernet_plugin.childrenList[0] + ix_net_ip_v4_v6_range = ix_net_ip_v4_v6_plugin.rangeList[0] + + ixload.update_network_address(net_traffic, "address", "gateway", + "prefix") + ix_net_ip_v4_v6_range.config.assert_called_once_with( + prefix="prefix", + ipAddress="address", + gatewayAddress="gateway") + + net_traffic.network.getL1Plugin.return_value = Exception + + with self.assertRaises(exceptions.InvalidRxfFile): + ixload.update_network_address(net_traffic, "address", "gateway", + "prefix") + + def test_update_network_param(self): + net_traffic = mock.Mock() + + ixload = http_ixload.IXLOADHttpTest( + jsonutils.dump_as_bytes(self.test_input)) + + ixload.update_network_address = mock.Mock() + ixload.update_network_mac_address = mock.Mock() + + param = {"address": "address", + "gateway": "gateway", + "subnet_prefix": "subnet_prefix", + "mac": "mac" + } + + ixload.update_network_param(net_traffic, param) + + ixload.update_network_address.assert_called_once_with(net_traffic, + "address", + "gateway", + "subnet_prefix") + + ixload.update_network_mac_address.assert_called_once_with( + net_traffic, + "mac") + @mock.patch('yardstick.network_services.traffic_profile.http_ixload.IxLoad') @mock.patch('yardstick.network_services.traffic_profile.http_ixload.StatCollectorUtils') def test_start_http_test(self, *args): @@ -224,6 +351,7 @@ class TestIxLoadTrafficGen(unittest.TestCase): "card": "CARD", "ports": ports, }, + 'links_param': {} } j = jsonutils.dump_as_bytes(test_input) @@ -248,6 +376,7 @@ class TestIxLoadTrafficGen(unittest.TestCase): "card": "CARD", "ports": ports, }, + 'links_param': {} } j = jsonutils.dump_as_bytes(test_input) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py b/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py index 0759ecebd..5b39b6cd1 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py @@ -586,7 +586,8 @@ class TestIXIARFC2544Profile(unittest.TestCase): 'Store-Forward_Max_latency_ns': 28} } rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) - completed, samples = rfc2544_profile.get_drop_percentage(samples, 0, 1) + completed, samples = rfc2544_profile.get_drop_percentage( + samples, 0, 1, 4) self.assertTrue(completed) self.assertEqual(66.9, samples['TxThroughput']) self.assertEqual(66.833, samples['RxThroughput']) @@ -610,7 +611,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) rfc2544_profile.rate = 1000 completed, samples = rfc2544_profile.get_drop_percentage( - samples, 0, 0.05) + samples, 0, 0.05, 4) self.assertFalse(completed) self.assertEqual(66.9, samples['TxThroughput']) self.assertEqual(66.833, samples['RxThroughput']) @@ -632,7 +633,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) rfc2544_profile.rate = 1000 completed, samples = rfc2544_profile.get_drop_percentage( - samples, 0.2, 1) + samples, 0.2, 1, 4) self.assertFalse(completed) self.assertEqual(66.9, samples['TxThroughput']) self.assertEqual(66.833, samples['RxThroughput']) @@ -655,7 +656,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) rfc2544_profile.rate = 1000 completed, samples = rfc2544_profile.get_drop_percentage( - samples, 0.2, 1) + samples, 0.2, 1, 4) self.assertFalse(completed) self.assertEqual(0.0, samples['TxThroughput']) self.assertEqual(66.833, samples['RxThroughput']) @@ -676,7 +677,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): } rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) completed, samples = rfc2544_profile.get_drop_percentage( - samples, 0, 1, first_run=True) + samples, 0, 1, 4, first_run=True) self.assertTrue(completed) self.assertEqual(66.9, samples['TxThroughput']) self.assertEqual(66.833, samples['RxThroughput']) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_prox_binsearch.py b/yardstick/tests/unit/network_services/traffic_profile/test_prox_binsearch.py index c09903377..4524eb7e6 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_prox_binsearch.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_prox_binsearch.py @@ -38,6 +38,12 @@ class TestProxBinSearchProfile(unittest.TestCase): return fail_tuple, {} return success_tuple, {} + def side_effect_func(arg1, arg2): + if arg1 == "confirmation": + return arg2 + else: + return {} + tp_config = { 'traffic_profile': { 'packet_sizes': [200], @@ -51,11 +57,13 @@ class TestProxBinSearchProfile(unittest.TestCase): fail_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.6, 5.7, 5.8], 850, 1000, 123.4) traffic_generator = mock.MagicMock() - attrs1 = {'get.return_value' : 10} + attrs1 = {'get.return_value': 10} traffic_generator.scenario_helper.all_options.configure_mock(**attrs1) - attrs2 = {'__getitem__.return_value' : 10, 'get.return_value': 10} + attrs2 = {'__getitem__.return_value': 10, 'get.return_value': 10} + attrs3 = {'get.side_effect': side_effect_func} traffic_generator.scenario_helper.scenario_cfg["runner"].configure_mock(**attrs2) + traffic_generator.scenario_helper.scenario_cfg["options"].configure_mock(**attrs3) profile_helper = mock.MagicMock() profile_helper.run_test = target @@ -68,7 +76,7 @@ class TestProxBinSearchProfile(unittest.TestCase): self.assertEqual(round(profile.current_lower, 2), 74.69) self.assertEqual(round(profile.current_upper, 2), 76.09) - self.assertEqual(len(runs), 77) + self.assertEqual(len(runs), 7) # Result Samples inc theor_max result_tuple = {'Actual_throughput': 5e-07, @@ -121,6 +129,12 @@ class TestProxBinSearchProfile(unittest.TestCase): return fail_tuple, {} return success_tuple, {} + def side_effect_func(arg1, _): + if arg1 == "confirmation": + return 2 + else: + return {} + tp_config = { 'traffic_profile': { 'packet_sizes': [200], @@ -138,7 +152,10 @@ class TestProxBinSearchProfile(unittest.TestCase): traffic_generator.scenario_helper.all_options.configure_mock(**attrs1) attrs2 = {'__getitem__.return_value': 0, 'get.return_value': 0} + attrs3 = {'get.side_effect': side_effect_func} + traffic_generator.scenario_helper.scenario_cfg["runner"].configure_mock(**attrs2) + traffic_generator.scenario_helper.scenario_cfg["options"].configure_mock(**attrs3) profile_helper = mock.MagicMock() profile_helper.run_test = target @@ -150,7 +167,7 @@ class TestProxBinSearchProfile(unittest.TestCase): profile.execute_traffic(traffic_generator) self.assertEqual(round(profile.current_lower, 2), 24.06) self.assertEqual(round(profile.current_upper, 2), 25.47) - self.assertEqual(len(runs), 7) + self.assertEqual(len(runs), 21) def test_execute_3(self): def target(*args, **_): @@ -186,8 +203,6 @@ class TestProxBinSearchProfile(unittest.TestCase): profile.lower_bound = 99.0 profile.execute_traffic(traffic_generator) - - # Result Samples result_tuple = {'Actual_throughput': 0, 'theor_max_throughput': 0, "Status": 'Result', "Next_Step": ''} profile.queue.put.assert_called_with(result_tuple) @@ -226,6 +241,7 @@ class TestProxBinSearchProfile(unittest.TestCase): traffic_generator.scenario_helper.all_options.configure_mock(**attrs1) attrs2 = {'__getitem__.return_value': 0, 'get.return_value': 0} + traffic_generator.scenario_helper.scenario_cfg["runner"].configure_mock(**attrs2) profile_helper = mock.MagicMock() diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py b/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py index cf31cc27c..11bee03a4 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py @@ -100,13 +100,13 @@ class TestProxProfile(unittest.TestCase): profile = ProxProfile(tp_config) - self.assertFalse(profile.done) + self.assertFalse(profile.done.is_set()) for _ in packet_sizes: with self.assertRaises(NotImplementedError): profile.execute_traffic(traffic_generator) self.assertIsNone(profile.execute_traffic(traffic_generator)) - self.assertTrue(profile.done) + self.assertTrue(profile.done.is_set()) def test_bounds_iterator(self): tp_config = { diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py index 3b095647c..3d6ebb25b 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py @@ -1527,14 +1527,16 @@ class TestProxResourceHelper(unittest.TestCase): def test_run_traffic(self): setup_helper = mock.MagicMock() helper = prox_helpers.ProxResourceHelper(setup_helper) - traffic_profile = mock.MagicMock(**{"done": True}) + traffic_profile = mock.MagicMock() + traffic_profile.done.is_set.return_value = True helper.run_traffic(traffic_profile) self.assertEqual(helper._terminated.value, 1) def test__run_traffic_once(self): setup_helper = mock.MagicMock() helper = prox_helpers.ProxResourceHelper(setup_helper) - traffic_profile = mock.MagicMock(**{"done": True}) + traffic_profile = mock.MagicMock() + traffic_profile.done.is_set.return_value = True helper._run_traffic_once(traffic_profile) self.assertEqual(helper._terminated.value, 1) diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py index 4a1d8c30e..c9d42fb3e 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py @@ -1206,6 +1206,7 @@ class TestRfc2544ResourceHelper(unittest.TestCase): self.assertIsNone(rfc2544_resource_helper._tolerance_high) self.assertEqual(rfc2544_resource_helper.tolerance_high, 0.15) self.assertEqual(rfc2544_resource_helper._tolerance_high, 0.15) + self.assertEqual(rfc2544_resource_helper._tolerance_precision, 2) scenario_helper.scenario_cfg = {} # ensure that resource_helper caches self.assertEqual(rfc2544_resource_helper.tolerance_high, 0.15) @@ -1240,6 +1241,7 @@ class TestRfc2544ResourceHelper(unittest.TestCase): rfc2544_resource_helper = Rfc2544ResourceHelper(scenario_helper) self.assertEqual(rfc2544_resource_helper.tolerance_high, 0.2) + self.assertEqual(rfc2544_resource_helper._tolerance_precision, 1) def test_property_tolerance_low_not_range(self): scenario_helper = ScenarioHelper('name1') diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py index 53474b96e..e7f6206eb 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py @@ -57,6 +57,7 @@ class TestIxLoadTrafficGen(ut_base.BaseUnitTestCase): 'external-interface': [{'virtual-interface': {'dst_mac': '00:00:00:00:00:04', + 'vld_id': 'uplink_0', 'vpci': '0000:05:00.0', 'local_ip': '152.16.100.19', 'type': 'PCI-PASSTHROUGH', @@ -71,6 +72,7 @@ class TestIxLoadTrafficGen(ut_base.BaseUnitTestCase): 'name': 'xe0'}, {'virtual-interface': {'dst_mac': '00:00:00:00:00:03', + 'vld_id': 'downlink_0', 'vpci': '0000:05:00.1', 'local_ip': '152.16.40.19', 'type': 'PCI-PASSTHROUGH', @@ -129,6 +131,17 @@ class TestIxLoadTrafficGen(ut_base.BaseUnitTestCase): ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') self.assertIsNone(ixload_traffic_gen.resource_helper.data) + def test_update_gateways(self): + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') + links = {'uplink_0': {'ip': {}}, + 'downlink_1': {'ip': {}}} + + ixload_traffic_gen.update_gateways(links) + + self.assertEqual("152.16.100.20", links["uplink_0"]["ip"]["gateway"]) + self.assertEqual("0.0.0.0", links["downlink_1"]["ip"]["gateway"]) + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') def test_collect_kpi(self, *args): @@ -189,6 +202,8 @@ class TestIxLoadTrafficGen(ut_base.BaseUnitTestCase): def test_run_traffic(self, *args): mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = '64' + mock_traffic_profile.get_links_param.return_value = { + 'uplink_0': {'ip': {}}} mock_traffic_profile.params = self.TRAFFIC_PROFILE vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] vnfd['mgmt-interface'].update({'tg-config': {}}) @@ -208,6 +223,8 @@ class TestIxLoadTrafficGen(ut_base.BaseUnitTestCase): def test_run_traffic_csv(self, *args): mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = '64' + mock_traffic_profile.get_links_param.return_value = { + 'uplink_0': {'ip': {}}} mock_traffic_profile.params = self.TRAFFIC_PROFILE vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] vnfd['mgmt-interface'].update({'tg-config': {}}) diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py index 53439972a..1736d0f17 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_landslide.py @@ -27,7 +27,7 @@ from yardstick.network_services import utils as net_serv_utils from yardstick.network_services.traffic_profile import landslide_profile from yardstick.network_services.vnf_generic.vnf import sample_vnf from yardstick.network_services.vnf_generic.vnf import tg_landslide - +from yardstick.network_services.vnf_generic.vnf import base as vnf_base NAME = "tg__0" @@ -337,6 +337,7 @@ class TestLandslideTrafficGen(unittest.TestCase): 'traffic_profile': '../../traffic_profiles/landslide/' 'landslide_dmf_udp.yaml', 'options': { + 'traffic_duration': 71, 'test_cases': [ { 'BearerAddrPool': '2002::2', @@ -465,8 +466,10 @@ class TestLandslideTrafficGen(unittest.TestCase): self.ls_tg.scenario_helper.scenario_cfg = self.SCENARIO_CFG mock_traffic_profile = mock.Mock( spec=landslide_profile.LandslideProfile) - mock_traffic_profile.dmf_config = {'keywords': 'UDP', - 'dataProtocol': 'udp'} + mock_traffic_profile.dmf_config = { + 'keywords': 'UDP', + 'dataProtocol': 'udp', + 'dmf': {'library': 'test', 'name': 'name'}} mock_traffic_profile.params = self.TRAFFIC_PROFILE self.ls_tg.resource_helper._user_id = self.TEST_USER_ID mock_get_tests.return_value = [{'id': self.SUCCESS_RECORD_ID, @@ -598,6 +601,28 @@ class TestLandslideTrafficGen(unittest.TestCase): get_session_tc_param_value(_key, _tc.get('type'), self.ls_tg.session_profile)) + def test__update_session_library_name(self, *args): + _session = copy.deepcopy(SESSION_PROFILE) + _session['tsGroups'].pop(0) + self.ls_tg.vnfd_helper = mock.MagicMock() + self.ls_tg.vnfd_helper.mgmt_interface.__getitem__.side_effect = { + 'user': TAS_INFO['user']} + self.ls_tg._update_session_library_name(_session) + _dmf = _session['tsGroups'][0]['testCases'][0]['parameters']['Dmf'] + # Expect DMF library name updated in Nodal test types + self.assertEqual(TAS_INFO['user'], _dmf['mainflows'][0]['library']) + + def test__update_session_library_name_wrong_tc_type(self, *args): + _session = copy.deepcopy(SESSION_PROFILE) + _session['tsGroups'].pop(1) + self.ls_tg.vnfd_helper = mock.MagicMock() + self.ls_tg.vnfd_helper.mgmt_interface.__getitem__.side_effect = { + 'user': TAS_INFO['user']} + # Expect DMF library name not updated in Node test types + self.assertNotIn('Dmf', + _session['tsGroups'][0]['testCases'][0]['parameters']) + self.ls_tg._update_session_library_name(_session) + @mock.patch.object(common_utils, 'open_relative_file') @mock.patch.object(yaml_loader, 'yaml_load') @mock.patch.object(tg_landslide.LandslideTrafficGen, @@ -986,11 +1011,15 @@ class TestLandslideResourceHelper(unittest.TestCase): def test_create_dmf(self, *args): self.res_helper._tcl = mock.Mock() + self.res_helper.vnfd_helper = mock.Mock(spec=vnf_base.VnfdHelper) + self.res_helper.vnfd_helper.mgmt_interface = {'user': TAS_INFO['user']} self.assertIsNone(self.res_helper.create_dmf(DMF_CFG)) self.res_helper._tcl.create_dmf.assert_called_once_with(DMF_CFG) def test_create_dmf_as_list(self, *args): self.res_helper._tcl = mock.Mock() + self.res_helper.vnfd_helper = mock.Mock(spec=vnf_base.VnfdHelper) + self.res_helper.vnfd_helper.mgmt_interface = {'user': TAS_INFO['user']} self.assertIsNone(self.res_helper.create_dmf([DMF_CFG])) self.res_helper._tcl.create_dmf.assert_called_once_with(DMF_CFG) @@ -1178,10 +1207,24 @@ class TestLandslideResourceHelper(unittest.TestCase): def test_create_test_session_res_helper(self, *args): self.res_helper._user_id = self.SUCCESS_RECORD_ID self.res_helper._tcl = mock.Mock() - test_session = {'name': 'test'} - self.assertIsNone(self.res_helper.create_test_session(test_session)) + self.res_helper.scenario_helper.all_options = {'traffic_duration': 71} + _session = {'name': 'test', 'duration': 60} + self.assertIsNone(self.res_helper.create_test_session(_session)) + self.res_helper._tcl.create_test_session.assert_called_once_with( + {'name': _session['name'], + 'duration': 71, + 'library': self.SUCCESS_RECORD_ID}) + + def test_create_test_session_res_helper_no_traffic_duration(self, *args): + self.res_helper._user_id = self.SUCCESS_RECORD_ID + self.res_helper._tcl = mock.Mock() + self.res_helper.scenario_helper.all_options = {} + _session = {'name': 'test', 'duration': 60} + self.assertIsNone(self.res_helper.create_test_session(_session)) self.res_helper._tcl.create_test_session.assert_called_once_with( - {'name': 'test', 'library': self.SUCCESS_RECORD_ID}) + {'name': _session['name'], + 'duration': 60, + 'library': self.SUCCESS_RECORD_ID}) @mock.patch.object(tg_landslide.LandslideTclClient, 'resolve_test_server_name', @@ -1597,7 +1640,7 @@ class TestLandslideTclClient(unittest.TestCase): self.mock_tcl_handler.execute.assert_has_calls([ mock.call('set dmf_ [ls::create Dmf]'), mock.call( - 'ls::get [ls::query LibraryInfo -systemLibraryName test] -Id'), + 'ls::get [ls::query LibraryInfo -systemLibraryName user] -Id'), mock.call('ls::config $dmf_ -Library 2 -Name "Basic UDP"'), mock.call('ls::config $dmf_ -dataProtocol "udp"'), # mock.call( @@ -1623,7 +1666,7 @@ class TestLandslideTclClient(unittest.TestCase): self.mock_tcl_handler.execute.assert_has_calls([ mock.call('set dmf_ [ls::create Dmf]'), mock.call( - 'ls::get [ls::query LibraryInfo -systemLibraryName test] -Id'), + 'ls::get [ls::query LibraryInfo -systemLibraryName user] -Id'), mock.call('ls::config $dmf_ -Library 2 -Name "Basic UDP"'), mock.call('ls::config $dmf_ -dataProtocol "udp"'), # mock.call( |