Message ID | cover.1601639563.git.qemu_oss@crudebyte.com |
---|---|
Headers | show |
Series | 9pfs: add tests using local fs driver | expand |
On Fri, Oct 02, 2020 at 04:09:53PM +0200, Christian Schoenebeck wrote: > On Freitag, 2. Oktober 2020 15:44:40 CEST Daniel P. Berrangé wrote: > > On Fri, Oct 02, 2020 at 03:41:07PM +0200, Christian Schoenebeck wrote: > > > On Freitag, 2. Oktober 2020 14:56:14 CEST Daniel P. Berrangé wrote: > > > > On Fri, Oct 02, 2020 at 01:51:54PM +0200, Christian Schoenebeck wrote: > > > > > This test case uses the 9pfs 'local' driver to create a directory > > > > > and then checks if the expected directory was actually created > > > > > (as real directory) on host side. > > > > > > > > > > Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com> > > > > > --- > > > > > > > > > > tests/qtest/virtio-9p-test.c | 139 > > > > > +++++++++++++++++++++++++++++++++++ > > > > > 1 file changed, 139 insertions(+) > > > > > > > > > > diff --git a/tests/qtest/virtio-9p-test.c > > > > > b/tests/qtest/virtio-9p-test.c > > > > > index af7e169d3a..93161a4b35 100644 > > > > > --- a/tests/qtest/virtio-9p-test.c > > > > > +++ b/tests/qtest/virtio-9p-test.c > > > > > @@ -18,6 +18,62 @@ > > > > > > > > > > #define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000) > > > > > static QGuestAllocator *alloc; > > > > > > > > > > +/* > > > > > + * Used to auto generate new fids. Start with arbitrary high value to > > > > > avoid + * collision with hard coded fids in basic test code. > > > > > + */ > > > > > +static uint32_t fid_generator = 1000; > > > > > + > > > > > +static uint32_t genfid(void) > > > > > +{ > > > > > + return fid_generator++; > > > > > +} > > > > > + > > > > > +/** > > > > > + * Splits the @a in string by @a delim into individual (non empty) > > > > > strings > > > > > + * and outputs them to @a out. The output array @a out is NULL > > > > > terminated. > > > > > + * > > > > > + * Output array @a out must be freed by calling split_free(). > > > > > + * > > > > > + * @returns number of individual elements in output array @a out > > > > > (without > > > > > the + * final NULL terminating element) > > > > > + */ > > > > > +static int split(const char *in, const char *delim, char ***out) > > > > > +{ > > > > > + int n = 0, i = 0; > > > > > + char *tmp, *p; > > > > > + > > > > > + tmp = g_strdup(in); > > > > > + for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) > > > > > { > > > > > + if (strlen(p) > 0) { > > > > > + ++n; > > > > > + } > > > > > + } > > > > > + g_free(tmp); > > > > > + > > > > > + *out = g_malloc0(n * sizeof(char *) + 1); /* last element NULL > > > > > delimiter */ > > > > > > > > Surely this should be (n + 1) * sizeof(char *), because the last > > > > element still needs to be large enough to hold a pointer, not a > > > > single extra byte. > > > > > > Right, good catch! > > > > > > > > + > > > > > + tmp = g_strdup(in); > > > > > + for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) > > > > > { > > > > > + if (strlen(p) > 0) { > > > > > + (*out)[i++] = g_strdup(p); > > > > > + } > > > > > + } > > > > > + g_free(tmp); > > > > > + > > > > > + return n; > > > > > +} > > > > > > > > This seems to largely re-invent g_strsplit > > > > > > > > https://developer.gnome.org/glib/2.62/glib-String-Utility-Functions.html > > > > #g-s trsplit > > > > > > Yes, except that g_strsplit() outputs empty array elements as well. That's > > > not desired/working for this patch. > > > > Either make the caller ignore/skip over empty elements, or make > > Not an option, since it would create too much test code overhead. I really > need [const int elements] and [array without empty elements]. > > > this method call g_strsplit and then filter out the empty elements. > > Mmm, so you're suggesting to allocate a new array, copy elements from > g_strsplit() array to the new array, and eventually pass that manually > allocated array to g_strfreev()? Wouldn't that be a bit unsafe regarding > potential future changes in how glib allocates/structures those string arrays? No need to realloate a new array - just shuffle down the elements in the array you get back from g_strsplit to discard the empty ones. Sure the array will end up with a series of NULLs at the end but that is harmless. both g_strsplit/g_strfreev work in terms of a normal allocated "char **" array, so there's no risk of changes to way memory is allocated. Regards, Daniel
On Freitag, 2. Oktober 2020 13:51:54 CEST Christian Schoenebeck wrote: > This patch introduces 9pfs test cases using the 9pfs 'local' > filesystem driver which reads/writes/creates/deletes real files > and directories. > > In this initial version, there is only one local test which actually > only checks if the 9pfs 'local' device was created successfully. > > Before the 9pfs 'local' tests are run, a test directory 'qtest-9p-local' > is created (with world rwx permissions) under the current working > directory. At this point that test directory is not auto deleted yet. > > Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com> > --- > tests/qtest/libqos/virtio-9p.c | 100 +++++++++++++++++++++++++++++++++ > tests/qtest/libqos/virtio-9p.h | 5 ++ > tests/qtest/virtio-9p-test.c | 44 ++++++++++----- > 3 files changed, 135 insertions(+), 14 deletions(-) > > diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c > index 2e300063e3..86e40e5d56 100644 > --- a/tests/qtest/libqos/virtio-9p.c > +++ b/tests/qtest/libqos/virtio-9p.c > @@ -24,6 +24,63 @@ > #include "qgraph.h" > > static QGuestAllocator *alloc; > +static char *local_test_path; > + > +static char *strpr(const char* format, ...) GCC_FMT_ATTR(1, 2); > + > +/* Concatenates the passed 2 pathes. Returned result must be freed. */ > +static char *concat_path(const char* a, const char* b) > +{ > + const int len = strlen(a) + strlen("/") + strlen(b); > + char *path = g_malloc0(len + 1); > + snprintf(path, len + 1, "%s/%s", a, b); > + g_assert(strlen(path) == len); > + return path; > +} Ok, but maybe I could make that concat_path() function wrap g_strconcat(). > + > +/* > + * Lazy sprintf() implementation which auto allocates buffer. Returned > result + * must be freed. > + */ > +static char *strpr(const char* format, ...) > +{ > + va_list argp; > + > + va_start(argp, format); > + const int sz = vsnprintf(NULL, 0, format, argp) + 1; > + va_end(argp); > + > + g_assert(sz > 0); > + char *s = g_malloc0(sz); > + > + va_start(argp, format); > + const int len = vsnprintf(s, sz, format, argp); > + va_end(argp); > + > + g_assert(len + 1 == sz); > + return s; > +} And this strpr() function entirely be replaced by g_strdup_printf(). > + > +static void init_local_test_path(void) > +{ > + char *pwd = get_current_dir_name(); > + local_test_path = concat_path(pwd, "qtest-9p-local"); > + free(pwd); > +} > + > +/* Creates the directory for the 9pfs 'local' filesystem driver to access. > */ +static void create_local_test_dir(void) > +{ > + struct stat st; > + > + g_assert(local_test_path != NULL); > + mkdir(local_test_path, 0777); > + > + /* ensure test directory exists now ... */ > + g_assert(stat(local_test_path, &st) == 0); > + /* ... and is actually a directory */ > + g_assert((st.st_mode & S_IFMT) == S_IFDIR); > +} > > static void virtio_9p_cleanup(QVirtio9P *interface) > { > @@ -146,11 +203,54 @@ static void *virtio_9p_pci_create(void *pci_bus, > QGuestAllocator *t_alloc, return obj; > } > > +void virtio_9p_assign_local_driver(GString *cmd_line, const char *args) > +{ > + GRegex *regex; > + char *s, *arg_repl; > + > + g_assert_nonnull(local_test_path); > + > + /* replace 'synth' driver by 'local' driver */ > + regex = g_regex_new("-fsdev synth,", 0, 0, NULL); > + s = g_regex_replace_literal( > + regex, cmd_line->str, -1, 0, "-fsdev local,", 0, NULL > + ); > + g_string_assign(cmd_line, s); > + g_free(s); > + g_regex_unref(regex); > + > + /* add 'path=...' to '-fsdev ...' group */ > + regex = g_regex_new("(-fsdev \\w+)(\\s*)", 0, 0, NULL); > + arg_repl = strpr("\\1\\2,path='%s'", local_test_path); > + s = g_regex_replace( > + regex, cmd_line->str, -1, 0, arg_repl, 0, NULL > + ); > + g_string_assign(cmd_line, s); > + g_free(arg_repl); > + g_free(s); > + g_regex_unref(regex); > + > + /* add passed args to '-fsdev ...' group */ > + regex = g_regex_new("(-fsdev \\w+)(\\s*)", 0, 0, NULL); > + arg_repl = strpr("\\1\\2,%s", args); > + s = g_regex_replace( > + regex, cmd_line->str, -1, 0, arg_repl, 0, NULL > + ); > + g_string_assign(cmd_line, s); > + g_free(arg_repl); > + g_free(s); > + g_regex_unref(regex); > +} > + > static void virtio_9p_register_nodes(void) > { > const char *str_simple = "fsdev=fsdev0,mount_tag=" MOUNT_TAG; > const char *str_addr = "fsdev=fsdev0,addr=04.0,mount_tag=" MOUNT_TAG; > > + /* make sure test dir for the 'local' tests exists and is clean */ > + init_local_test_path(); > + create_local_test_dir(); > + > QPCIAddress addr = { > .devfn = QPCI_DEVFN(4, 0), > }; > diff --git a/tests/qtest/libqos/virtio-9p.h b/tests/qtest/libqos/virtio-9p.h > index b1e6badc4a..326a603f72 100644 > --- a/tests/qtest/libqos/virtio-9p.h > +++ b/tests/qtest/libqos/virtio-9p.h > @@ -44,4 +44,9 @@ struct QVirtio9PDevice { > QVirtio9P v9p; > }; > > +/** > + * Prepares QEMU command line for 9pfs tests using the 'local' fs driver. > + */ > +void virtio_9p_assign_local_driver(GString *cmd_line, const char *args); > + > #endif > diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c > index 3281153b9c..af7e169d3a 100644 > --- a/tests/qtest/virtio-9p-test.c > +++ b/tests/qtest/virtio-9p-test.c > @@ -895,29 +895,45 @@ static void fs_readdir_split_512(void *obj, void > *data, fs_readdir_split(obj, data, t_alloc, 512); > } > > +static void *assign_9p_local_driver(GString *cmd_line, void *arg) > +{ > + virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr"); > + return arg; > +} > + > static void register_virtio_9p_test(void) > { > - qos_add_test("synth/config", "virtio-9p", pci_config, NULL); > - qos_add_test("synth/version/basic", "virtio-9p", fs_version, NULL); > - qos_add_test("synth/attach/basic", "virtio-9p", fs_attach, NULL); > - qos_add_test("synth/walk/basic", "virtio-9p", fs_walk, NULL); > + > + QOSGraphTestOptions opts = { > + }; > + > + /* 9pfs test cases using the 'synth' filesystem driver */ > + qos_add_test("synth/config", "virtio-9p", pci_config, &opts); > + qos_add_test("synth/version/basic", "virtio-9p", fs_version, &opts); > + qos_add_test("synth/attach/basic", "virtio-9p", fs_attach, &opts); > + qos_add_test("synth/walk/basic", "virtio-9p", fs_walk, &opts); > qos_add_test("synth/walk/no_slash", "virtio-9p", fs_walk_no_slash, > - NULL); > + &opts); > qos_add_test("synth/walk/dotdot_from_root", "virtio-9p", > - fs_walk_dotdot, NULL); > - qos_add_test("synth/lopen/basic", "virtio-9p", fs_lopen, NULL); > - qos_add_test("synth/write/basic", "virtio-9p", fs_write, NULL); > + fs_walk_dotdot, &opts); > + qos_add_test("synth/lopen/basic", "virtio-9p", fs_lopen, &opts); > + qos_add_test("synth/write/basic", "virtio-9p", fs_write, &opts); > qos_add_test("synth/flush/success", "virtio-9p", fs_flush_success, > - NULL); > + &opts); > qos_add_test("synth/flush/ignored", "virtio-9p", fs_flush_ignored, > - NULL); > - qos_add_test("synth/readdir/basic", "virtio-9p", fs_readdir, NULL); > + &opts); > + qos_add_test("synth/readdir/basic", "virtio-9p", fs_readdir, &opts); > qos_add_test("synth/readdir/split_512", "virtio-9p", > - fs_readdir_split_512, NULL); > + fs_readdir_split_512, &opts); > qos_add_test("synth/readdir/split_256", "virtio-9p", > - fs_readdir_split_256, NULL); > + fs_readdir_split_256, &opts); > qos_add_test("synth/readdir/split_128", "virtio-9p", > - fs_readdir_split_128, NULL); > + fs_readdir_split_128, &opts); > + > + > + /* 9pfs test cases using the 'local' filesystem driver */ > + opts.before = assign_9p_local_driver; > + qos_add_test("local/config", "virtio-9p", pci_config, &opts); > } > > libqos_init(register_virtio_9p_test); Best regards, Christian Schoenebeck
On Fri, Oct 02, 2020 at 04:26:48PM +0200, Christian Schoenebeck wrote: > On Freitag, 2. Oktober 2020 13:51:54 CEST Christian Schoenebeck wrote: > > This patch introduces 9pfs test cases using the 9pfs 'local' > > filesystem driver which reads/writes/creates/deletes real files > > and directories. > > > > In this initial version, there is only one local test which actually > > only checks if the 9pfs 'local' device was created successfully. > > > > Before the 9pfs 'local' tests are run, a test directory 'qtest-9p-local' > > is created (with world rwx permissions) under the current working > > directory. At this point that test directory is not auto deleted yet. > > > > Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com> > > --- > > tests/qtest/libqos/virtio-9p.c | 100 +++++++++++++++++++++++++++++++++ > > tests/qtest/libqos/virtio-9p.h | 5 ++ > > tests/qtest/virtio-9p-test.c | 44 ++++++++++----- > > 3 files changed, 135 insertions(+), 14 deletions(-) > > > > diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c > > index 2e300063e3..86e40e5d56 100644 > > --- a/tests/qtest/libqos/virtio-9p.c > > +++ b/tests/qtest/libqos/virtio-9p.c > > @@ -24,6 +24,63 @@ > > #include "qgraph.h" > > > > static QGuestAllocator *alloc; > > +static char *local_test_path; > > + > > +static char *strpr(const char* format, ...) GCC_FMT_ATTR(1, 2); > > + > > +/* Concatenates the passed 2 pathes. Returned result must be freed. */ > > +static char *concat_path(const char* a, const char* b) > > +{ > > + const int len = strlen(a) + strlen("/") + strlen(b); > > + char *path = g_malloc0(len + 1); > > + snprintf(path, len + 1, "%s/%s", a, b); > > + g_assert(strlen(path) == len); > > + return path; > > +} > > Ok, but maybe I could make that concat_path() function wrap g_strconcat(). Or even one of g_build_path or g_build_filename may be useful > > +/* > > + * Lazy sprintf() implementation which auto allocates buffer. Returned > > result + * must be freed. > > + */ > > +static char *strpr(const char* format, ...) > > +{ > > + va_list argp; > > + > > + va_start(argp, format); > > + const int sz = vsnprintf(NULL, 0, format, argp) + 1; > > + va_end(argp); > > + > > + g_assert(sz > 0); > > + char *s = g_malloc0(sz); > > + > > + va_start(argp, format); > > + const int len = vsnprintf(s, sz, format, argp); > > + va_end(argp); > > + > > + g_assert(len + 1 == sz); > > + return s; > > +} > > And this strpr() function entirely be replaced by g_strdup_printf(). Yep, its preferrable to use g_strdup_printf instead of manually allocating. Regards, Daniel