test suite reviews and discussions
 help / color / mirror / Atom feed
From: "Tu, Lijuan" <lijuan.tu@intel.com>
To: "Mo, YufengX" <yufengx.mo@intel.com>,
	"dts@dpdk.org" <dts@dpdk.org>, "Wan, Zhe" <zhe.wan@intel.com>
Cc: "Mo, YufengX" <yufengx.mo@intel.com>
Subject: Re: [dts] [PATCH V1 1/1] tests/telemetry: upload suite script
Date: Wed, 18 Sep 2019 05:34:47 +0000	[thread overview]
Message-ID: <8CE3E05A3F976642AAB0F4675D0AD20E0BB23B18@SHSMSX101.ccr.corp.intel.com> (raw)
In-Reply-To: <20190902023506.11416-2-yufengx.mo@intel.com>

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 <zhe.wan@intel.com>
> Cc: Mo, YufengX <yufengx.mo@intel.com>
> Subject: [dts] [PATCH V1 1/1] tests/telemetry: upload suite script
> 
> 
> The telemetry mechanism provides the functionality so that users may query
> metrics from incoming port traffic and global stats(application stats).
> The application which initializes packet forwarding will act as the server,
> sending metrics to the requesting application which acts as the client.
> 
> Signed-off-by: yufengmx <yufengx.mo@intel.com>
> ---
>  tests/TestSuite_telemetry.py | 586
> +++++++++++++++++++++++++++++++++++
>  1 file changed, 586 insertions(+)
>  create mode 100644 tests/TestSuite_telemetry.py
> 
> 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 = (
> +            "sed -i -e "
> +
> "'s/CONFIG_RTE_LIBRTE_TELEMETRY=n/CONFIG_RTE_LIBRTE_TELEMETRY=y/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 = 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 = 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 client
> +                    self.socket.client_fd.send(METRICS_REQ)
> +                    data = self.socket.client_fd.recv(BUFFER_SIZE)
> +                    return data
> +                def singleRequestMetrics(self):
> +                    data = self.requestMetrics()
> +                    self.save_date(data)
> +                def repeatedlyRequestMetrics(self, sleep_time=1, n_requests=2):
> +                    data_list = {}
> +                    for i in range(n_requests):
> +                        data_list[i] = self.requestMetrics()
> +                        time.sleep(sleep_time)
> +                    self.save_date(data_list)
> +            parser = argparse.ArgumentParser(description='dpdk telemetry tool')
> +            parser.add_argument('-c',
> +                                '--choice',
> +                                nargs='*',
> +                                default=1,
> +                                help='choice option')
> +            parser.add_argument('-n',
> +                                '--n_requests',
> +                                nargs='*',
> +                                default=1,
> +                                help='n requests option')
> +            parser.add_argument('-j',
> +                                '--json_file',
> +                                nargs='*',
> +                                default=None,
> +                                help='json file directory')
> +            print("Options Menu")
> +            args = parser.parse_args()
> +            if not args.choice or not len(args.choice):
> +                print("Error - Invalid request choice")
> +            else:
> +                file_path = DEFAULT_FP
> +                client = ClientExd(args.json_file[0])
> +                client.getFilepath(file_path)
> +                client.register()
> +                choice = int(args.choice[0])
> +                if choice == 1:
> +                    print("[1] Send for Metrics for all ports")
> +                    client.singleRequestMetrics()
> +                elif choice == 2:
> +                    print("[2] Send for Metrics for all ports recursively")
> +                    client.repeatedlyRequestMetrics(1)
> +                time.sleep(2)
> +                print("Unregister client")
> +                client.unregister()
> +                client.unregistered = 1
> +                print("Get metrics done")
> +        """)
> +        fileName = 'query_tool.py'
> +        query_script = os.path.join(self.output_path, fileName)
> +        with open(query_script, 'wb') as fp:
> +            fp.write('#! /usr/bin/env python' + os.linesep + script_content)
> +        self.dut.session.copy_file_to(query_script, self.target_dir)
> +        self.query_tool = ';'.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 = 'dpdk_telemetry_client.py'
> +        old_name = 'dpdk-telemetry-client.py'
> +        cmds = [
> +            '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 = ';'.join(cmds).format(self.target_dir, new_name, old_name)
> +        self.d_a_console(cmd)
> +        self.create_query_script()
> +
> +    @property
> +    def target_dir(self):
> +        # get absolute directory of target source code
> +        target_dir = '/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 = self.__class__.__name__[4:].lower()
> +        if self.logger.log_path.startswith(os.sep):
> +            output_path = os.path.join(self.logger.log_path, suiteName)
> +        else:
> +            cur_path = os.path.dirname(
> +                os.path.dirname(os.path.realpath(__file__)))
> +            output_path = 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='dut')
> +
> +    def d_a_console(self, cmds):
> +        return self.execute_cmds(cmds, con_name='dut_alt')
> +
> +    def get_console(self, name):
> +        if name == 'dut':
> +            console = self.dut.send_expect
> +            msg_pipe = self.dut.get_session_output
> +        elif name == 'dut_alt':
> +            console = self.dut.alt_session.send_expect
> +            msg_pipe = self.dut.alt_session.session.get_output_all
> +        else:
> +            msg = '{} not created'.format(name)
> +            raise Exception(msg)
> +        return console, msg_pipe
> +
> +    def execute_cmds(self, cmds, con_name='dut'):
> +        console, msg_pipe = self.get_console(con_name)
> +        if not cmds:
> +            return
> +        if isinstance(cmds, (str, unicode)):
> +            cmds = [cmds, '# ', 5]
> +        if not isinstance(cmds[0], list):
> +            cmds = [cmds]
> +        outputs = [] if len(cmds) > 1 else ''
> +        for item in cmds:
> +            expected_items = item[1]
> +            expected_str = expected_items or '# '
> +            try:
> +                timeout = int(item[2]) if len(item) == 3 else 5
> +                output = console(item[0], expected_str, timeout)
> +            except Exception as e:
> +                # self.check_process_status()
> +                msg = "execute '{0}' timeout".format(item[0])
> +                raise Exception(msg)
> +            time.sleep(1)
> +            if len(cmds) > 1:
> +                outputs.append(output)
> +            else:
> +                outputs = 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 = 'close'
> +        self.testpmd = PmdOutput(self.dut)
> +        # prepare telemetry tool
> +        self.rename_dpdk_telemetry_tool()
> +
> +    def get_whitelist(self, num=1, nic_types=2):
> +        self.used_ports = []
> +        if len(self.dut_ports) < 4 or len(self.nic_grp) < nic_types:
> +            self.used_ports = self.dut_ports
> +            return None
> +        pci_addrs = [
> +            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 = self.dut.ports_info[index]
> +            if info['pci'] not in pci_addrs:
> +                continue
> +            self.used_ports.append(index)
> +        white_list = ' '.join(['-w ' + pci_addr for pci_addr in pci_addrs])
> +        return white_list
> +
> +    def start_telemetry_server(self, whitelist=None):
> +        if self.testpmd_status != 'close':
> +            return None
> +        # use dut first port's socket
> +        socket = self.dut.get_numa_id(0)
> +        config = "Default"
> +        eal_option = '--telemetry ' + whitelist if whitelist else '--telemetry'
> +        output = self.testpmd.start_testpmd(config,
> +                                            eal_param=eal_option,
> +                                            socket=socket)
> +        self.testpmd_status = 'running'
> +        self.testpmd.execute_cmd('start')
> +        return output
> +
> +    def close_telemetry_server(self):
> +        if self.testpmd_status == 'close':
> +            return None
> +        self.testpmd.execute_cmd('stop')
> +        self.testpmd.quit()
> +        self.testpmd_status = 'close'
> +
> +    def get_all_xstat_data(self):
> +        ''' get nic extended statistics '''
> +        cmd = ['show port xstats all', 'testpmd>']
> +        output = self.d_console(cmd)
> +        if "statistics" not in output:
> +            self.logger.error(output)
> +            raise Exception("failed to get port extended statistics data")
> +        data_str = output.splitlines()
> +        port_xstat = {}
> +        cur_port = None
> +        pat = r".*extended statistics for port (\d+).*"
> +        for line in data_str:
> +            if not line.strip():
> +                continue
> +            if "statistics" in line:
> +                result = re.findall(pat, line.strip())
> +                if len(result):
> +                    cur_port = int(result[0])
> +            elif cur_port is not None and ": " in line:
> +                if cur_port not in port_xstat:
> +                    port_xstat[cur_port] = {}
> +                result = line.strip().split(": ")
> +                if len(result) == 2 and result[0]:
> +                    name, value = result
> +                    port_xstat[cur_port][name] = int(value)
> +                else:
> +                    raise Exception("invalid data")
> +
> +        return port_xstat
> +
> +    def get_metric_data(self):
> +        json_name = 'metric.json'
> +        json_file = os.path.join(self.target_dir, json_name)
> +        cmd = "{0} -c 1 -j {1}".format(self.query_tool, json_file)
> +        output = self.d_a_console(cmd)
> +        msg = 'faile to query metric data'
> +        self.verify("Get metrics done" in output, msg)
> +        dst_file = os.path.join(self.output_path, json_name)
> +        self.dut.session.copy_file_from(json_file, dst_file)
> +        msg = 'failed to get {}'.format(json_name)
> +        self.verify(os.path.exists(dst_file), msg)
> +        with open(dst_file, 'r') as fp:
> +            try:
> +                query_data = json.load(fp, encoding="utf-8")
> +            except Exception as e:
> +                msg = 'failed to load metrics json data'
> +                self.verify(False, msg)
> +        metric_status = query_data.get('status_code')
> +        msg = 'failed to query metric data, return status <{}>'.format(
> +            metric_status)
> +        self.verify('Status OK' in metric_status, msg)
> +        metric_data = {}
> +        for info in query_data.get('data'):
> +            port_index = info.get('port')
> +            stats = info.get('stats')
> +            metric_data[port_index] = {}
> +            for stat in stats:
> +                metric_data[port_index][stat.get('name')] = \
> +                    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 = self.start_telemetry_client()
> +        # check script select items
> +        expected_strs = [
> +            'Send for Metrics for all ports',
> +            'Send for Metrics for all ports recursively',
> +            'Send for global Metrics',
> +            'Unregister client', ]
> +        msg = 'expected select items not existed'
> +        self.verify(all([item in output for item in expected_strs]), msg)
> +        cmd = ['1', ':', 10]
> +        output = self.dut_s_session.send_expect(*cmd)
> +        output = self.dut_s_session.session.get_output_all()
> +        cmd = ['4', '#', 5]
> +        output = self.dut_s_session.send_expect(*cmd)
> +
> +    def start_telemetry_client(self):
> +        self.dut_s_session = self.dut.new_session()
> +        dpdk_tool = os.path.join(
> +            self.target_dir, 'usertools/dpdk-telemetry-client.py')
> +        output = self.dut_s_session.send_expect(dpdk_tool, ':', 5)
> +        return output
> +
> +    def close_telemetry_client(self):
> +        cmd = "ps aux | grep -i '%s' | grep -v grep | awk {'print $2'}" % (
> +            'dpdk-telemetry-client.py')
> +        out = self.d_a_console([cmd, '# ', 5])
> +        if out != "" and '[PEXPECT]' not in out:
> +            process_pid = out.splitlines()[0]
> +            cmd = ['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 = self.get_metric_data()
> +        msg = "haven't get all ports metric data"
> +        self.verify(len(self.used_ports) == len(metric_data), msg)
> +        port_index_list = range(len(self.used_ports))
> +        for port_index in metric_data:
> +            msg = '<{}> is not the expected port'.format(port_index)
> +            self.verify(
> +                port_index is not None and port_index in port_index_list, msg)
> +        output = self.dut.get_session_output()
> +        self.verify('failed' not in output, output)
> +        # set rx/tx configuration by testpmd
> +        cmds = [
> +            ['stop', 'testpmd>', 15],
> +            ['clear port xstats all', 'testpmd>', 15]]
> +        self.d_console(cmds)
> +        metric_data = self.get_metric_data()
> +        xstats = self.get_all_xstat_data()
> +        self.compare_data(metric_data, xstats)
> +
> +    def compare_data(self, metric, xstat):
> +        error_msg = []
> +        # Ensure # of ports stats being returned == # of ports
> +        msg = "metric and xstat data are not the same"
> +        self.verify(len(metric) == len(xstat), msg)
> +        # check if parameters are the same
> +        for port_id in metric:
> +            if len(metric[0]) == len(xstat[0]):
> +                continue
> +            xstat_missed_paras = []
> +            for keyname in metric[0].keys():
> +                if keyname in xstat[0].keys():
> +                    continue
> +                xstat_missed_paras.append(keyname)
> +            metric_missed_paras = []
> +            for keyname in xstat[0].keys():
> +                if keyname in metric[0].keys():
> +                    continue
> +                metric_missed_paras.append(keyname)
> +            msg = 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) != 0:
> +            msg = 'telemetry metric data is not the same as testpmd xstat data'
> +            error_msg.append(msg)
> +            msg_fmt = 'port {} <{}>: metric is <{}>, xstat is is <{}>'.format
> +            for port_index, info in metric.iteritems():
> +                for name, value in info.iteritems():
> +                    if value == xstat[port_index][str(name)]:
> +                        continue
> +                    error_msg.append(msg_fmt(port_index, name,
> +                                             value, xstat[port_index][name]))
> +        # check if metric parameters value should be zero
> +        # ensure extended NIC stats are 0
> +        is_clear = any([any(data.values()) for data in metric.values()])
> +        if is_clear:
> +            msg = 'telemetry metric data are not default value'
> +            error_msg.append(msg)
> +            msg_fmt = '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 = {}
> +        for info in self.dut.ports_info:
> +            nic_type = info['type']
> +            if nic_type not in nic_grp:
> +                nic_grp[nic_type] = []
> +            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 = self.get_metric_data()
> +            port_index_list = range(len(self.dut_ports))
> +            msg = "haven't get all ports metric data"
> +            self.verify(len(self.dut_ports) == len(metric_data), msg)
> +            for port_index in metric_data:
> +                msg = '<{}> is not the expected port'.format(port_index)
> +                self.verify(
> +                    port_index is not None and port_index in port_index_list,
> +                    msg)
> +            output = 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 = os.linesep.join(['no enough ports', pformat(self.nic_grp)])
> +        self.verify(len(self.nic_grp.values()[0]) >= 2, msg)
> +        try:
> +            # check and verify error show on testpmd
> +            whitelist = self.get_whitelist(num=2, nic_types=1)
> +            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 = os.linesep.join(['no enough ports, 4 ports at least',
> +                               pformat(self.nic_grp)])
> +        self.verify(len(self.nic_grp.values()[0]) >= 4, msg)
> +        try:
> +            self.used_ports = 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 = os.linesep.join(['no enough nic types, 2 nic types at least',
> +                               pformat(self.nic_grp)])
> +        self.verify(len(self.nic_grp.keys()) >= 2, msg)
> +        try:
> +            whitelist = 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 = os.linesep.join(['no enough nic types, 2 nic types at least',
> +                               pformat(self.nic_grp)])
> +        self.verify(len(self.nic_grp.keys()) >= 2, msg)
> +        msg = os.linesep.join(['no enough ports, 2 ports/nic type at least',
> +                               pformat(self.nic_grp)])
> +        self.verify(
> +            all([pci_addrs and len(pci_addrs) >= 2
> +                 for pci_addrs in self.nic_grp.values()]),
> +            msg)
> +
> +        try:
> +            self.used_ports = 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 = self.dut.get_ports()
> +        self.verify(len(self.dut_ports) >= 2, "Insufficient ports")
> +        self.init_test_binary_files()
> +        self.nic_grp = self.get_ports_by_nic_type()
> +        self.used_ports = []
> +
> +    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


      parent reply	other threads:[~2019-09-18  5:34 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-09-02  2:35 [dts] [PATCH V1 0/1] " yufengmx
2019-09-02  2:35 ` [dts] [PATCH V1 1/1] " yufengmx
2019-09-06  5:45   ` Wan, Zhe
2019-09-18  5:34   ` Tu, Lijuan [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8CE3E05A3F976642AAB0F4675D0AD20E0BB23B18@SHSMSX101.ccr.corp.intel.com \
    --to=lijuan.tu@intel.com \
    --cc=dts@dpdk.org \
    --cc=yufengx.mo@intel.com \
    --cc=zhe.wan@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).