[v1,3/3] test/devargs: add devargs test cases

Message ID 20211005155435.279043-4-xuemingl@nvidia.com (mailing list archive)
State Superseded, archived
Delegated to: David Marchand
Headers
Series devargs: support path in global syntax |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/Intel-compilation success Compilation OK
ci/intel-Testing success Testing PASS
ci/iol-aarch64-compile-testing success Testing PASS
ci/github-robot: build fail github build: failed
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-x86_64-compile-testing fail Testing issues
ci/iol-x86_64-unit-testing fail Testing issues

Commit Message

Xueming Li Oct. 5, 2021, 3:54 p.m. UTC
  Initial version to test Global devargs syntax.

Signed-off-by: Xueming Li <xuemingl@nvidia.com>
---
 app/test/autotest_data.py |   6 ++
 app/test/meson.build      |   2 +
 app/test/test_devargs.c   | 147 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+)
 create mode 100644 app/test/test_devargs.c
  

Comments

Gaëtan Rivet Oct. 19, 2021, 3:07 p.m. UTC | #1
On Tue, Oct 5, 2021, at 17:54, Xueming Li wrote:
> Initial version to test Global devargs syntax.
>
> Signed-off-by: Xueming Li <xuemingl@nvidia.com>

Hi,

The test is a very nice addition, absolutely required.
I have however two remarks on the coverage and the implementation, below.

> ---
>  app/test/autotest_data.py |   6 ++
>  app/test/meson.build      |   2 +
>  app/test/test_devargs.c   | 147 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 155 insertions(+)
>  create mode 100644 app/test/test_devargs.c
>
> diff --git a/app/test/autotest_data.py b/app/test/autotest_data.py
> index 302d6374c16..3b841e71918 100644
> --- a/app/test/autotest_data.py
> +++ b/app/test/autotest_data.py
> @@ -785,6 +785,12 @@
>          "Func":    default_autotest,
>          "Report":  None,
>      },
> +    {
> +        "Name":    "Devargs autotest",
> +        "Command": "devargs_autotest",
> +        "Func":    default_autotest,
> +        "Report":  None,
> +    },
>      #
>      # Please always make sure that ring_perf is the last test!
>      #
> diff --git a/app/test/meson.build b/app/test/meson.build
> index f144d8b8ed6..de8540f6119 100644
> --- a/app/test/meson.build
> +++ b/app/test/meson.build
> @@ -42,6 +42,7 @@ test_sources = files(
>          'test_cryptodev_security_pdcp.c',
>          'test_cycles.c',
>          'test_debug.c',
> +        'test_devargs.c',
>          'test_distributor.c',
>          'test_distributor_perf.c',
>          'test_eal_flags.c',
> @@ -201,6 +202,7 @@ fast_tests = [
>          ['common_autotest', true],
>          ['cpuflags_autotest', true],
>          ['debug_autotest', true],
> +        ['devargs_autotest', true],
>          ['eal_flags_c_opt_autotest', false],
>          ['eal_flags_main_opt_autotest', false],
>          ['eal_flags_n_opt_autotest', false],
> diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c
> new file mode 100644
> index 00000000000..8a173368347
> --- /dev/null
> +++ b/app/test/test_devargs.c
> @@ -0,0 +1,147 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright (c) 2021 NVIDIA Corporation & Affiliates
> + */
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +#include <rte_common.h>
> +#include <rte_devargs.h>
> +#include <rte_kvargs.h>
> +
> +#include "test.h"
> +
> +/* Check layer arguments. */
> +static int
> +test_args(const char *devargs, const char *layer, const char *args, 
> const int n)
> +{
> +	struct rte_kvargs *kvlist;
> +
> +	if (n == 0) {
> +		if (args != NULL && strlen(args) > 0) {
> +			printf("rte_devargs_parse(%s) %s args parsed (not expected)\n",
> +			       devargs, layer);
> +			return -1;
> +		} else {
> +			return 0;
> +		}
> +	}
> +	if (args == NULL) {
> +		printf("rte_devargs_parse(%s) %s args not parsed\n",
> +		       devargs, layer);
> +		return -1;
> +	}
> +	kvlist = rte_kvargs_parse(args, NULL);
> +	if (kvlist == NULL) {
> +		printf("rte_devargs_parse(%s) %s_str: %s not parsed\n",
> +		       devargs, layer, args);
> +		return -1;
> +	}
> +	if ((int)kvlist->count != n) {
> +		printf("rte_devargs_parse(%s) %s_str: %s kv number %u, not %d\n",
> +		       devargs, layer, args, kvlist->count, n);
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +/* Test several valid cases */
> +static int
> +test_valid_devargs(void)
> +{
> +	static const struct {
> +		const char *devargs;
> +		int bus_kv;
> +		int class_kv;
> +		int driver_kv;
> +	} list[] = {
> +		/* Global devargs syntax: */
> +		{ "bus=pci", 1, 0, 0 },
> +		{ "class=eth", 0, 1, 0 },
> +		{ "bus=pci,addr=1:2.3/class=eth/driver=abc,k0=v0", 2, 1, 2 },
> +		{ "bus=vdev,name=/dev/file/name/class=eth", 2, 1, 0 },
> +		/* Legacy devargs syntax: */
> +		{ "1:2.3", 0, 0, 0 },
> +		{ "pci:1:2.3,k0=v0", 0, 0, 1 },
> +		{ "net_virtio_user0,iface=test,path=/dev/vhost-net,queues=1",
> +		  0, 0, 3 },

I would add here cases to verify that edge-case are properly parsed such as:

+               { "bus=vdev,name=/class/bus/path/class=eth", 2, 1, 0 },
[...]
+               { "net_virtio_user0,iface=test,path=/class/bus/,queues=1",
+                 0, 0, 3 },

To check the /class or /bus parts cannot throw off the parser (it does not currently).

Additionally, paths with multiple slashes are correct. Maybe add:

+               { "bus=vdev,name=///dblslsh/class=eth", 2, 1, 0 },

as well.

I tested all those cases without issue, it seems the parser is ok.


A second point is that the test only verifies that the numbers of kv were found.
I think this is not robust enough. Instead, I think the 'expect' part of the test
should describe exactly what each layers should be within the devargs (which bus,
class and driver are expected to be found, and the associated string).

Right now the parser could mangle part of a key-value list within the string,
recognize each layers and give incorrect strings to each layer parser.

It might be too much? I don't know. But it seems it could help ensure no error
is introduced at some point by future changes.
  
Xueming Li Oct. 20, 2021, 7:20 a.m. UTC | #2
On Tue, 2021-10-19 at 17:07 +0200, Gaëtan Rivet wrote:
> On Tue, Oct 5, 2021, at 17:54, Xueming Li wrote:
> > Initial version to test Global devargs syntax.
> > 
> > Signed-off-by: Xueming Li <xuemingl@nvidia.com>
> 
> Hi,
> 
> The test is a very nice addition, absolutely required.
> I have however two remarks on the coverage and the implementation, below.
> 
> > ---
> >  app/test/autotest_data.py |   6 ++
> >  app/test/meson.build      |   2 +
> >  app/test/test_devargs.c   | 147 ++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 155 insertions(+)
> >  create mode 100644 app/test/test_devargs.c
> > 
> > diff --git a/app/test/autotest_data.py b/app/test/autotest_data.py
> > index 302d6374c16..3b841e71918 100644
> > --- a/app/test/autotest_data.py
> > +++ b/app/test/autotest_data.py
> > @@ -785,6 +785,12 @@
> >          "Func":    default_autotest,
> >          "Report":  None,
> >      },
> > +    {
> > +        "Name":    "Devargs autotest",
> > +        "Command": "devargs_autotest",
> > +        "Func":    default_autotest,
> > +        "Report":  None,
> > +    },
> >      #
> >      # Please always make sure that ring_perf is the last test!
> >      #
> > diff --git a/app/test/meson.build b/app/test/meson.build
> > index f144d8b8ed6..de8540f6119 100644
> > --- a/app/test/meson.build
> > +++ b/app/test/meson.build
> > @@ -42,6 +42,7 @@ test_sources = files(
> >          'test_cryptodev_security_pdcp.c',
> >          'test_cycles.c',
> >          'test_debug.c',
> > +        'test_devargs.c',
> >          'test_distributor.c',
> >          'test_distributor_perf.c',
> >          'test_eal_flags.c',
> > @@ -201,6 +202,7 @@ fast_tests = [
> >          ['common_autotest', true],
> >          ['cpuflags_autotest', true],
> >          ['debug_autotest', true],
> > +        ['devargs_autotest', true],
> >          ['eal_flags_c_opt_autotest', false],
> >          ['eal_flags_main_opt_autotest', false],
> >          ['eal_flags_n_opt_autotest', false],
> > diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c
> > new file mode 100644
> > index 00000000000..8a173368347
> > --- /dev/null
> > +++ b/app/test/test_devargs.c
> > @@ -0,0 +1,147 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright (c) 2021 NVIDIA Corporation & Affiliates
> > + */
> > +
> > +#include <stdlib.h>
> > +#include <stdio.h>
> > +#include <string.h>
> > +
> > +#include <rte_common.h>
> > +#include <rte_devargs.h>
> > +#include <rte_kvargs.h>
> > +
> > +#include "test.h"
> > +
> > +/* Check layer arguments. */
> > +static int
> > +test_args(const char *devargs, const char *layer, const char *args, 
> > const int n)
> > +{
> > +	struct rte_kvargs *kvlist;
> > +
> > +	if (n == 0) {
> > +		if (args != NULL && strlen(args) > 0) {
> > +			printf("rte_devargs_parse(%s) %s args parsed (not expected)\n",
> > +			       devargs, layer);
> > +			return -1;
> > +		} else {
> > +			return 0;
> > +		}
> > +	}
> > +	if (args == NULL) {
> > +		printf("rte_devargs_parse(%s) %s args not parsed\n",
> > +		       devargs, layer);
> > +		return -1;
> > +	}
> > +	kvlist = rte_kvargs_parse(args, NULL);
> > +	if (kvlist == NULL) {
> > +		printf("rte_devargs_parse(%s) %s_str: %s not parsed\n",
> > +		       devargs, layer, args);
> > +		return -1;
> > +	}
> > +	if ((int)kvlist->count != n) {
> > +		printf("rte_devargs_parse(%s) %s_str: %s kv number %u, not %d\n",
> > +		       devargs, layer, args, kvlist->count, n);
> > +		return -1;
> > +	}
> > +	return 0;
> > +}
> > +
> > +/* Test several valid cases */
> > +static int
> > +test_valid_devargs(void)
> > +{
> > +	static const struct {
> > +		const char *devargs;
> > +		int bus_kv;
> > +		int class_kv;
> > +		int driver_kv;
> > +	} list[] = {
> > +		/* Global devargs syntax: */
> > +		{ "bus=pci", 1, 0, 0 },
> > +		{ "class=eth", 0, 1, 0 },
> > +		{ "bus=pci,addr=1:2.3/class=eth/driver=abc,k0=v0", 2, 1, 2 },
> > +		{ "bus=vdev,name=/dev/file/name/class=eth", 2, 1, 0 },
> > +		/* Legacy devargs syntax: */
> > +		{ "1:2.3", 0, 0, 0 },
> > +		{ "pci:1:2.3,k0=v0", 0, 0, 1 },
> > +		{ "net_virtio_user0,iface=test,path=/dev/vhost-net,queues=1",
> > +		  0, 0, 3 },
> 
> I would add here cases to verify that edge-case are properly parsed such as:
> 
> +               { "bus=vdev,name=/class/bus/path/class=eth", 2, 1, 0 },
> [...]
> +               { "net_virtio_user0,iface=test,path=/class/bus/,queues=1",
> +                 0, 0, 3 },
> 
> To check the /class or /bus parts cannot throw off the parser (it does not currently).
> 
> Additionally, paths with multiple slashes are correct. Maybe add:
> 
> +               { "bus=vdev,name=///dblslsh/class=eth", 2, 1, 0 },
> 
> as well.
> 
> I tested all those cases without issue, it seems the parser is ok.
> 
> 
> A second point is that the test only verifies that the numbers of kv were found.
> I think this is not robust enough. Instead, I think the 'expect' part of the test
> should describe exactly what each layers should be within the devargs (which bus,
> class and driver are expected to be found, and the associated string).
> 
> Right now the parser could mangle part of a key-value list within the string,
> recognize each layers and give incorrect strings to each layer parser.
> 
> It might be too much? I don't know. But it seems it could help ensure no error
> is introduced at some point by future changes.
> 

Good suggestion, will added them in v2, thanks!
  

Patch

diff --git a/app/test/autotest_data.py b/app/test/autotest_data.py
index 302d6374c16..3b841e71918 100644
--- a/app/test/autotest_data.py
+++ b/app/test/autotest_data.py
@@ -785,6 +785,12 @@ 
         "Func":    default_autotest,
         "Report":  None,
     },
+    {
+        "Name":    "Devargs autotest",
+        "Command": "devargs_autotest",
+        "Func":    default_autotest,
+        "Report":  None,
+    },
     #
     # Please always make sure that ring_perf is the last test!
     #
diff --git a/app/test/meson.build b/app/test/meson.build
index f144d8b8ed6..de8540f6119 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -42,6 +42,7 @@  test_sources = files(
         'test_cryptodev_security_pdcp.c',
         'test_cycles.c',
         'test_debug.c',
+        'test_devargs.c',
         'test_distributor.c',
         'test_distributor_perf.c',
         'test_eal_flags.c',
@@ -201,6 +202,7 @@  fast_tests = [
         ['common_autotest', true],
         ['cpuflags_autotest', true],
         ['debug_autotest', true],
+        ['devargs_autotest', true],
         ['eal_flags_c_opt_autotest', false],
         ['eal_flags_main_opt_autotest', false],
         ['eal_flags_n_opt_autotest', false],
diff --git a/app/test/test_devargs.c b/app/test/test_devargs.c
new file mode 100644
index 00000000000..8a173368347
--- /dev/null
+++ b/app/test/test_devargs.c
@@ -0,0 +1,147 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2021 NVIDIA Corporation & Affiliates
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_devargs.h>
+#include <rte_kvargs.h>
+
+#include "test.h"
+
+/* Check layer arguments. */
+static int
+test_args(const char *devargs, const char *layer, const char *args, const int n)
+{
+	struct rte_kvargs *kvlist;
+
+	if (n == 0) {
+		if (args != NULL && strlen(args) > 0) {
+			printf("rte_devargs_parse(%s) %s args parsed (not expected)\n",
+			       devargs, layer);
+			return -1;
+		} else {
+			return 0;
+		}
+	}
+	if (args == NULL) {
+		printf("rte_devargs_parse(%s) %s args not parsed\n",
+		       devargs, layer);
+		return -1;
+	}
+	kvlist = rte_kvargs_parse(args, NULL);
+	if (kvlist == NULL) {
+		printf("rte_devargs_parse(%s) %s_str: %s not parsed\n",
+		       devargs, layer, args);
+		return -1;
+	}
+	if ((int)kvlist->count != n) {
+		printf("rte_devargs_parse(%s) %s_str: %s kv number %u, not %d\n",
+		       devargs, layer, args, kvlist->count, n);
+		return -1;
+	}
+	return 0;
+}
+
+/* Test several valid cases */
+static int
+test_valid_devargs(void)
+{
+	static const struct {
+		const char *devargs;
+		int bus_kv;
+		int class_kv;
+		int driver_kv;
+	} list[] = {
+		/* Global devargs syntax: */
+		{ "bus=pci", 1, 0, 0 },
+		{ "class=eth", 0, 1, 0 },
+		{ "bus=pci,addr=1:2.3/class=eth/driver=abc,k0=v0", 2, 1, 2 },
+		{ "bus=vdev,name=/dev/file/name/class=eth", 2, 1, 0 },
+		/* Legacy devargs syntax: */
+		{ "1:2.3", 0, 0, 0 },
+		{ "pci:1:2.3,k0=v0", 0, 0, 1 },
+		{ "net_virtio_user0,iface=test,path=/dev/vhost-net,queues=1",
+		  0, 0, 3 },
+	};
+	struct rte_devargs da;
+	uint32_t i;
+	int ret;
+	int fail = 0;
+
+	for (i = 0; i < RTE_DIM(list); i++) {
+		memset(&da, 0, sizeof(da));
+		ret = rte_devargs_parse(&da, list[i].devargs);
+		if (ret < 0) {
+			printf("rte_devargs_parse(%s) returned %d (but should not)\n",
+			       list[i].devargs, ret);
+			goto fail;
+		}
+		if (list[i].bus_kv > 0 && da.bus == NULL) {
+			printf("rte_devargs_parse(%s) bus not parsed\n",
+			       list[i].devargs);
+			goto fail;
+		}
+		if (test_args(list[i].devargs, "bus", da.bus_str,
+			      list[i].bus_kv) != 0)
+			goto fail;
+		if (list[i].class_kv > 0 && da.cls == NULL) {
+			printf("rte_devargs_parse(%s) class not parsed\n",
+			       list[i].devargs);
+			goto fail;
+		}
+		if (test_args(list[i].devargs, "class", da.cls_str,
+			      list[i].class_kv) != 0)
+			goto fail;
+		if (test_args(list[i].devargs, "driver", da.drv_str,
+			      list[i].driver_kv) != 0)
+			goto fail;
+		goto cleanup;
+fail:
+		fail = -1;
+cleanup:
+		rte_devargs_reset(&da);
+	}
+	return fail;
+}
+
+/* Test several invalid cases */
+static int
+test_invalid_devargs(void)
+{
+	static const char * const list[] = {
+		"bus=wrong-bus",
+		"class=wrong-class"};
+	struct rte_devargs da;
+	uint32_t i;
+	int ret;
+	int fail = 0;
+
+	for (i = 0; i < RTE_DIM(list); i++) {
+		ret = rte_devargs_parse(&da, list[i]);
+		if (ret >= 0) {
+			printf("rte_devargs_parse(%s) returned %d (but should not)\n",
+			       list[i], ret);
+			fail = ret;
+		}
+		rte_devargs_reset(&da);
+	}
+	return fail;
+}
+
+static int
+test_devargs(void)
+{
+	printf("== test valid case ==\n");
+	if (test_valid_devargs() < 0)
+		return -1;
+	printf("== test invalid case ==\n");
+	if (test_invalid_devargs() < 0)
+		return -1;
+	return 0;
+}
+
+REGISTER_TEST_COMMAND(devargs_autotest, test_devargs);