From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id A8548A2EFC for ; Wed, 18 Sep 2019 07:34:53 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 9F1141BF83; Wed, 18 Sep 2019 07:34:53 +0200 (CEST) Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by dpdk.org (Postfix) with ESMTP id 60DDA1BF79 for ; Wed, 18 Sep 2019 07:34:52 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 17 Sep 2019 22:34:51 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,519,1559545200"; d="scan'208";a="216823867" Received: from fmsmsx104.amr.corp.intel.com ([10.18.124.202]) by fmsmga002.fm.intel.com with ESMTP; 17 Sep 2019 22:34:50 -0700 Received: from fmsmsx156.amr.corp.intel.com (10.18.116.74) by fmsmsx104.amr.corp.intel.com (10.18.124.202) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 17 Sep 2019 22:34:50 -0700 Received: from shsmsx151.ccr.corp.intel.com (10.239.6.50) by fmsmsx156.amr.corp.intel.com (10.18.116.74) with Microsoft SMTP Server (TLS) id 14.3.439.0; Tue, 17 Sep 2019 22:34:50 -0700 Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.92]) by SHSMSX151.ccr.corp.intel.com ([169.254.3.53]) with mapi id 14.03.0439.000; Wed, 18 Sep 2019 13:34:47 +0800 From: "Tu, Lijuan" To: "Mo, YufengX" , "dts@dpdk.org" , "Wan, Zhe" CC: "Mo, YufengX" Thread-Topic: [dts] [PATCH V1 1/1] tests/telemetry: upload suite script Thread-Index: AQHVYTbnC4XL62/ySU6MLta1MLkd16cxAxZw Date: Wed, 18 Sep 2019 05:34:47 +0000 Message-ID: <8CE3E05A3F976642AAB0F4675D0AD20E0BB23B18@SHSMSX101.ccr.corp.intel.com> References: <20190902023506.11416-1-yufengx.mo@intel.com> <20190902023506.11416-2-yufengx.mo@intel.com> In-Reply-To: <20190902023506.11416-2-yufengx.mo@intel.com> Accept-Language: zh-CN, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: dlp-product: dlpe-windows dlp-version: 11.2.0.6 dlp-reaction: no-action x-ctpclassification: CTP_NT x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiOWM5ZGYwMmMtNTQ5Mi00Y2RjLThlMjctMjkwZWVhM2NhODk2IiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX05UIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjEwLjE4MDQuNDkiLCJUcnVzdGVkTGFiZWxIYXNoIjoiaFBNSnVUT3FwdWsyaUZ3elwvQUJOMk5VeHdQeno0MElnbTQ3VWpPaHhlVmt2UTJMWHNVSTV2TitiZk1JbmxnM0gifQ== x-originating-ip: [10.239.127.40] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dts] [PATCH V1 1/1] tests/telemetry: upload suite script X-BeenThere: dts@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: test suite reviews and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dts-bounces@dpdk.org Sender: "dts" Applied, thanks > -----Original Message----- > From: dts [mailto:dts-bounces@dpdk.org] On Behalf Of yufengmx > Sent: Monday, September 2, 2019 10:35 AM > To: dts@dpdk.org; Wan, Zhe > Cc: Mo, YufengX > Subject: [dts] [PATCH V1 1/1] tests/telemetry: upload suite script >=20 >=20 > The telemetry mechanism provides the functionality so that users may quer= y > metrics from incoming port traffic and global stats(application stats). > The application which initializes packet forwarding will act as the serve= r, > sending metrics to the requesting application which acts as the client. >=20 > Signed-off-by: yufengmx > --- > tests/TestSuite_telemetry.py | 586 > +++++++++++++++++++++++++++++++++++ > 1 file changed, 586 insertions(+) > create mode 100644 tests/TestSuite_telemetry.py >=20 > diff --git a/tests/TestSuite_telemetry.py b/tests/TestSuite_telemetry.py = new > file mode 100644 index 0000000..bb2c9e6 > --- /dev/null > +++ b/tests/TestSuite_telemetry.py > @@ -0,0 +1,586 @@ > +# BSD LICENSE > +# > +# Copyright(c) 2010-2019 Intel Corporation. All rights reserved. > +# All rights reserved. > +# > +# Redistribution and use in source and binary forms, with or without # > +modification, are permitted provided that the following conditions # > +are met: > +# > +# * Redistributions of source code must retain the above copyright > +# notice, this list of conditions and the following disclaimer. > +# * Redistributions in binary form must reproduce the above copyright > +# notice, this list of conditions and the following disclaimer in > +# the documentation and/or other materials provided with the > +# distribution. > +# * Neither the name of Intel Corporation nor the names of its > +# contributors may be used to endorse or promote products derived > +# from this software without specific prior written permission. > +# > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > CONTRIBUTORS # > +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # > +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS > FOR # > +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE > COPYRIGHT # > +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, > INCIDENTAL, # > +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > # > +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > USE, # > +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND > ON ANY # > +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # > +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE > USE # > +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > + > +import os > +import time > +import json > +import re > +import textwrap > +from pprint import pformat > + > +# import dts libs > +from test_case import TestCase > +from pmd_output import PmdOutput > + > + > +class TestTelemetry(TestCase): > + > + def set_compiler_switch(self): > + cmd =3D ( > + "sed -i -e " > + > "'s/CONFIG_RTE_LIBRTE_TELEMETRY=3Dn/CONFIG_RTE_LIBRTE_TELEMETRY=3Dy/g > '" > + " {}/config/common_base").format(self.target_dir) > + self.d_a_console(cmd) > + > + def create_query_script(self): > + ''' > + usertools/dpdk-telemetry-client.py is not user friendly(till 19.= 05). > + this method is used to make sure testing robust. > + ''' > + script_content =3D textwrap.dedent(""" > + #! /usr/bin/env python > + import argparse > + import time > + import json > + from dpdk_telemetry_client import Client, DEFAULT_FP, > + METRICS_REQ, BUFFER_SIZE > + > + class ClientExd(Client): > + def __init__(self, json_file): > + super(ClientExd, self).__init__() > + self.json_file =3D json_file > + def save_date(self, data): > + with open(self.json_file, 'w') as fp: > + fp.write(data) > + def requestMetrics(self): # Requests metrics for given c= lient > + self.socket.client_fd.send(METRICS_REQ) > + data =3D self.socket.client_fd.recv(BUFFER_SIZE) > + return data > + def singleRequestMetrics(self): > + data =3D self.requestMetrics() > + self.save_date(data) > + def repeatedlyRequestMetrics(self, sleep_time=3D1, n_req= uests=3D2): > + data_list =3D {} > + for i in range(n_requests): > + data_list[i] =3D self.requestMetrics() > + time.sleep(sleep_time) > + self.save_date(data_list) > + parser =3D argparse.ArgumentParser(description=3D'dpdk telem= etry tool') > + parser.add_argument('-c', > + '--choice', > + nargs=3D'*', > + default=3D1, > + help=3D'choice option') > + parser.add_argument('-n', > + '--n_requests', > + nargs=3D'*', > + default=3D1, > + help=3D'n requests option') > + parser.add_argument('-j', > + '--json_file', > + nargs=3D'*', > + default=3DNone, > + help=3D'json file directory') > + print("Options Menu") > + args =3D parser.parse_args() > + if not args.choice or not len(args.choice): > + print("Error - Invalid request choice") > + else: > + file_path =3D DEFAULT_FP > + client =3D ClientExd(args.json_file[0]) > + client.getFilepath(file_path) > + client.register() > + choice =3D int(args.choice[0]) > + if choice =3D=3D 1: > + print("[1] Send for Metrics for all ports") > + client.singleRequestMetrics() > + elif choice =3D=3D 2: > + print("[2] Send for Metrics for all ports recursivel= y") > + client.repeatedlyRequestMetrics(1) > + time.sleep(2) > + print("Unregister client") > + client.unregister() > + client.unregistered =3D 1 > + print("Get metrics done") > + """) > + fileName =3D 'query_tool.py' > + query_script =3D os.path.join(self.output_path, fileName) > + with open(query_script, 'wb') as fp: > + fp.write('#! /usr/bin/env python' + os.linesep + script_cont= ent) > + self.dut.session.copy_file_to(query_script, self.target_dir) > + self.query_tool =3D ';'.join([ > + 'cd {}'.format(self.target_dir), > + 'chmod 777 {}'.format(fileName), > + './' + fileName]) > + > + def rename_dpdk_telemetry_tool(self): > + ''' > + transfer dpdk-telemetry-client.py to the available python module > + ''' > + new_name =3D 'dpdk_telemetry_client.py' > + old_name =3D 'dpdk-telemetry-client.py' > + cmds =3D [ > + 'rm -f {0}/{1}', > + 'cp -f {0}/usertools/dpdk-telemetry-client.py {0}/{1}', > + "sed -i -e 's/class Client:/class Client(object):/g' {0}/{1}= "] > + cmd =3D ';'.join(cmds).format(self.target_dir, new_name, old_nam= e) > + self.d_a_console(cmd) > + self.create_query_script() > + > + @property > + def target_dir(self): > + # get absolute directory of target source code > + target_dir =3D '/root' + self.dut.base_dir[1:] \ > + if self.dut.base_dir.startswith('~') else \ > + self.dut.base_dir > + return target_dir > + > + @property > + def output_path(self): > + suiteName =3D self.__class__.__name__[4:].lower() > + if self.logger.log_path.startswith(os.sep): > + output_path =3D os.path.join(self.logger.log_path, suiteName= ) > + else: > + cur_path =3D os.path.dirname( > + os.path.dirname(os.path.realpath(__file__))) > + output_path =3D os.path.join( > + cur_path, self.logger.log_path, suiteName) > + if not os.path.exists(output_path): > + os.makedirs(output_path) > + > + return output_path > + > + def d_console(self, cmds): > + return self.execute_cmds(cmds, con_name=3D'dut') > + > + def d_a_console(self, cmds): > + return self.execute_cmds(cmds, con_name=3D'dut_alt') > + > + def get_console(self, name): > + if name =3D=3D 'dut': > + console =3D self.dut.send_expect > + msg_pipe =3D self.dut.get_session_output > + elif name =3D=3D 'dut_alt': > + console =3D self.dut.alt_session.send_expect > + msg_pipe =3D self.dut.alt_session.session.get_output_all > + else: > + msg =3D '{} not created'.format(name) > + raise Exception(msg) > + return console, msg_pipe > + > + def execute_cmds(self, cmds, con_name=3D'dut'): > + console, msg_pipe =3D self.get_console(con_name) > + if not cmds: > + return > + if isinstance(cmds, (str, unicode)): > + cmds =3D [cmds, '# ', 5] > + if not isinstance(cmds[0], list): > + cmds =3D [cmds] > + outputs =3D [] if len(cmds) > 1 else '' > + for item in cmds: > + expected_items =3D item[1] > + expected_str =3D expected_items or '# ' > + try: > + timeout =3D int(item[2]) if len(item) =3D=3D 3 else 5 > + output =3D console(item[0], expected_str, timeout) > + except Exception as e: > + # self.check_process_status() > + msg =3D "execute '{0}' timeout".format(item[0]) > + raise Exception(msg) > + time.sleep(1) > + if len(cmds) > 1: > + outputs.append(output) > + else: > + outputs =3D output > + return outputs > + > + def init_test_binary_files(self): > + # set_compiler_switch > + if not self.dut.skip_setup: > + self.set_compiler_switch() > + self.dut.build_install_dpdk(self.target) > + # initialize testpmd > + self.testpmd_status =3D 'close' > + self.testpmd =3D PmdOutput(self.dut) > + # prepare telemetry tool > + self.rename_dpdk_telemetry_tool() > + > + def get_whitelist(self, num=3D1, nic_types=3D2): > + self.used_ports =3D [] > + if len(self.dut_ports) < 4 or len(self.nic_grp) < nic_types: > + self.used_ports =3D self.dut_ports > + return None > + pci_addrs =3D [ > + pci_addr for pci_addrs in self.nic_grp.values()[:nic_types] > + for pci_addr in pci_addrs[:num]] > + for index in self.dut_ports: > + info =3D self.dut.ports_info[index] > + if info['pci'] not in pci_addrs: > + continue > + self.used_ports.append(index) > + white_list =3D ' '.join(['-w ' + pci_addr for pci_addr in pci_ad= drs]) > + return white_list > + > + def start_telemetry_server(self, whitelist=3DNone): > + if self.testpmd_status !=3D 'close': > + return None > + # use dut first port's socket > + socket =3D self.dut.get_numa_id(0) > + config =3D "Default" > + eal_option =3D '--telemetry ' + whitelist if whitelist else '--t= elemetry' > + output =3D self.testpmd.start_testpmd(config, > + eal_param=3Deal_option, > + socket=3Dsocket) > + self.testpmd_status =3D 'running' > + self.testpmd.execute_cmd('start') > + return output > + > + def close_telemetry_server(self): > + if self.testpmd_status =3D=3D 'close': > + return None > + self.testpmd.execute_cmd('stop') > + self.testpmd.quit() > + self.testpmd_status =3D 'close' > + > + def get_all_xstat_data(self): > + ''' get nic extended statistics ''' > + cmd =3D ['show port xstats all', 'testpmd>'] > + output =3D self.d_console(cmd) > + if "statistics" not in output: > + self.logger.error(output) > + raise Exception("failed to get port extended statistics data= ") > + data_str =3D output.splitlines() > + port_xstat =3D {} > + cur_port =3D None > + pat =3D r".*extended statistics for port (\d+).*" > + for line in data_str: > + if not line.strip(): > + continue > + if "statistics" in line: > + result =3D re.findall(pat, line.strip()) > + if len(result): > + cur_port =3D int(result[0]) > + elif cur_port is not None and ": " in line: > + if cur_port not in port_xstat: > + port_xstat[cur_port] =3D {} > + result =3D line.strip().split(": ") > + if len(result) =3D=3D 2 and result[0]: > + name, value =3D result > + port_xstat[cur_port][name] =3D int(value) > + else: > + raise Exception("invalid data") > + > + return port_xstat > + > + def get_metric_data(self): > + json_name =3D 'metric.json' > + json_file =3D os.path.join(self.target_dir, json_name) > + cmd =3D "{0} -c 1 -j {1}".format(self.query_tool, json_file) > + output =3D self.d_a_console(cmd) > + msg =3D 'faile to query metric data' > + self.verify("Get metrics done" in output, msg) > + dst_file =3D os.path.join(self.output_path, json_name) > + self.dut.session.copy_file_from(json_file, dst_file) > + msg =3D 'failed to get {}'.format(json_name) > + self.verify(os.path.exists(dst_file), msg) > + with open(dst_file, 'r') as fp: > + try: > + query_data =3D json.load(fp, encoding=3D"utf-8") > + except Exception as e: > + msg =3D 'failed to load metrics json data' > + self.verify(False, msg) > + metric_status =3D query_data.get('status_code') > + msg =3D 'failed to query metric data, return status <{}>'.format= ( > + metric_status) > + self.verify('Status OK' in metric_status, msg) > + metric_data =3D {} > + for info in query_data.get('data'): > + port_index =3D info.get('port') > + stats =3D info.get('stats') > + metric_data[port_index] =3D {} > + for stat in stats: > + metric_data[port_index][stat.get('name')] =3D \ > + int(stat.get('value')) > + self.logger.debug(pformat(metric_data)) > + return metric_data > + > + def check_telemetry_client_script(self): > + ''' > + check if dpdk-telemetry-client.py is available > + ''' > + output =3D self.start_telemetry_client() > + # check script select items > + expected_strs =3D [ > + 'Send for Metrics for all ports', > + 'Send for Metrics for all ports recursively', > + 'Send for global Metrics', > + 'Unregister client', ] > + msg =3D 'expected select items not existed' > + self.verify(all([item in output for item in expected_strs]), msg= ) > + cmd =3D ['1', ':', 10] > + output =3D self.dut_s_session.send_expect(*cmd) > + output =3D self.dut_s_session.session.get_output_all() > + cmd =3D ['4', '#', 5] > + output =3D self.dut_s_session.send_expect(*cmd) > + > + def start_telemetry_client(self): > + self.dut_s_session =3D self.dut.new_session() > + dpdk_tool =3D os.path.join( > + self.target_dir, 'usertools/dpdk-telemetry-client.py') > + output =3D self.dut_s_session.send_expect(dpdk_tool, ':', 5) > + return output > + > + def close_telemetry_client(self): > + cmd =3D "ps aux | grep -i '%s' | grep -v grep | awk {'print $2'}= " % ( > + 'dpdk-telemetry-client.py') > + out =3D self.d_a_console([cmd, '# ', 5]) > + if out !=3D "" and '[PEXPECT]' not in out: > + process_pid =3D out.splitlines()[0] > + cmd =3D ['kill -TERM {0}'.format(process_pid), '# '] > + self.d_a_console(cmd) > + self.dut.close_session(self.dut_s_session) > + > + def check_metric_data(self): > + metric_data =3D self.get_metric_data() > + msg =3D "haven't get all ports metric data" > + self.verify(len(self.used_ports) =3D=3D len(metric_data), msg) > + port_index_list =3D range(len(self.used_ports)) > + for port_index in metric_data: > + msg =3D '<{}> is not the expected port'.format(port_index) > + self.verify( > + port_index is not None and port_index in port_index_list= , msg) > + output =3D self.dut.get_session_output() > + self.verify('failed' not in output, output) > + # set rx/tx configuration by testpmd > + cmds =3D [ > + ['stop', 'testpmd>', 15], > + ['clear port xstats all', 'testpmd>', 15]] > + self.d_console(cmds) > + metric_data =3D self.get_metric_data() > + xstats =3D self.get_all_xstat_data() > + self.compare_data(metric_data, xstats) > + > + def compare_data(self, metric, xstat): > + error_msg =3D [] > + # Ensure # of ports stats being returned =3D=3D # of ports > + msg =3D "metric and xstat data are not the same" > + self.verify(len(metric) =3D=3D len(xstat), msg) > + # check if parameters are the same > + for port_id in metric: > + if len(metric[0]) =3D=3D len(xstat[0]): > + continue > + xstat_missed_paras =3D [] > + for keyname in metric[0].keys(): > + if keyname in xstat[0].keys(): > + continue > + xstat_missed_paras.append(keyname) > + metric_missed_paras =3D [] > + for keyname in xstat[0].keys(): > + if keyname in metric[0].keys(): > + continue > + metric_missed_paras.append(keyname) > + msg =3D os.linesep.join([ > + 'testpmd xstat missed parameters:: ', > + pformat(xstat_missed_paras), > + 'telemetry metric missed parameters:: ', > + pformat(metric_missed_paras), ]) > + error_msg.append(msg) > + # check if metric parameters and values are the same > + if cmp(metric, xstat) !=3D 0: > + msg =3D 'telemetry metric data is not the same as testpmd xs= tat data' > + error_msg.append(msg) > + msg_fmt =3D 'port {} <{}>: metric is <{}>, xstat is is <{}>'= .format > + for port_index, info in metric.iteritems(): > + for name, value in info.iteritems(): > + if value =3D=3D xstat[port_index][str(name)]: > + continue > + error_msg.append(msg_fmt(port_index, name, > + value, xstat[port_index][na= me])) > + # check if metric parameters value should be zero > + # ensure extended NIC stats are 0 > + is_clear =3D any([any(data.values()) for data in metric.values()= ]) > + if is_clear: > + msg =3D 'telemetry metric data are not default value' > + error_msg.append(msg) > + msg_fmt =3D 'port {} <{}>: metric is <{}>'.format > + for port_index, info in metric.iteritems(): > + for name, value in info.iteritems(): > + if not value: > + continue > + error_msg.append(msg_fmt(port_index, name, value)) > + # show exception check content > + if error_msg: > + self.logger.error(os.linesep.join(error_msg)) > + self.verify(False, 'telemetry metric data error') > + > + def get_ports_by_nic_type(self): > + nic_grp =3D {} > + for info in self.dut.ports_info: > + nic_type =3D info['type'] > + if nic_type not in nic_grp: > + nic_grp[nic_type] =3D [] > + nic_grp[nic_type].append(info['pci']) > + return nic_grp > + # > + # test content > + # > + > + def verify_basic_script(self): > + ''' > + verify dpdk-telemetry-client.py script > + ''' > + try: > + self.start_telemetry_server() > + time.sleep(1) > + self.check_telemetry_client_script() > + self.close_telemetry_client() > + self.close_telemetry_server() > + except Exception as e: > + self.close_telemetry_client() > + self.close_telemetry_server() > + raise Exception(e) > + > + def verify_basic_connection(self): > + try: > + self.start_telemetry_server() > + metric_data =3D self.get_metric_data() > + port_index_list =3D range(len(self.dut_ports)) > + msg =3D "haven't get all ports metric data" > + self.verify(len(self.dut_ports) =3D=3D len(metric_data), msg= ) > + for port_index in metric_data: > + msg =3D '<{}> is not the expected port'.format(port_inde= x) > + self.verify( > + port_index is not None and port_index in port_index_= list, > + msg) > + output =3D self.dut.get_session_output() > + self.verify('failed' not in output, output) > + self.close_telemetry_server() > + except Exception as e: > + self.close_telemetry_server() > + raise Exception(e) > + > + def verify_same_nic_with_2ports(self): > + msg =3D os.linesep.join(['no enough ports', pformat(self.nic_grp= )]) > + self.verify(len(self.nic_grp.values()[0]) >=3D 2, msg) > + try: > + # check and verify error show on testpmd > + whitelist =3D self.get_whitelist(num=3D2, nic_types=3D1) > + self.start_telemetry_server(whitelist) > + # check telemetry metric data > + self.check_metric_data() > + self.close_telemetry_server() > + except Exception as e: > + self.close_telemetry_server() > + raise Exception(e) > + > + def verify_same_nic_with_4ports(self): > + msg =3D os.linesep.join(['no enough ports, 4 ports at least', > + pformat(self.nic_grp)]) > + self.verify(len(self.nic_grp.values()[0]) >=3D 4, msg) > + try: > + self.used_ports =3D self.dut_ports > + self.start_telemetry_server() > + # check telemetry metric data > + self.check_metric_data() > + self.close_telemetry_server() > + except Exception as e: > + self.close_telemetry_server() > + raise Exception(e) > + > + def verify_different_nic_with_2ports(self): > + # check ports total number > + msg =3D os.linesep.join(['no enough nic types, 2 nic types at le= ast', > + pformat(self.nic_grp)]) > + self.verify(len(self.nic_grp.keys()) >=3D 2, msg) > + try: > + whitelist =3D self.get_whitelist() > + self.start_telemetry_server(whitelist) > + # check telemetry metric data > + self.check_metric_data() > + self.close_telemetry_server() > + except Exception as e: > + self.close_telemetry_server() > + raise Exception(e) > + > + def verify_different_nic_with_4ports(self): > + msg =3D os.linesep.join(['no enough nic types, 2 nic types at le= ast', > + pformat(self.nic_grp)]) > + self.verify(len(self.nic_grp.keys()) >=3D 2, msg) > + msg =3D os.linesep.join(['no enough ports, 2 ports/nic type at l= east', > + pformat(self.nic_grp)]) > + self.verify( > + all([pci_addrs and len(pci_addrs) >=3D 2 > + for pci_addrs in self.nic_grp.values()]), > + msg) > + > + try: > + self.used_ports =3D self.dut_ports > + self.start_telemetry_server() > + # check telemetry metric data > + self.check_metric_data() > + self.close_telemetry_server() > + except Exception as e: > + self.close_telemetry_server() > + raise Exception(e) > + # > + # Test cases. > + # > + > + def set_up_all(self): > + """ > + Run before each test suite > + """ > + # get ports information > + self.dut_ports =3D self.dut.get_ports() > + self.verify(len(self.dut_ports) >=3D 2, "Insufficient ports") > + self.init_test_binary_files() > + self.nic_grp =3D self.get_ports_by_nic_type() > + self.used_ports =3D [] > + > + def set_up(self): > + """ > + Run before each test case. > + """ > + pass > + > + def tear_down(self): > + """ > + Run after each test case. > + """ > + pass > + > + def tear_down_all(self): > + """ > + Run after each test suite. > + """ > + pass > + > + def test_basic_connection(self): > + ''' > + basic connection for testpmd and telemetry client > + ''' > + self.verify_basic_script() > + self.verify_basic_connection() > + > + def test_same_nic_with_2ports(self): > + ''' > + Stats of 2 ports for testpmd and telemetry with same type nic > + ''' > + self.verify_same_nic_with_2ports() > -- > 2.21.0