As promised in the previous patch, also test the new nbd_opt_set_meta_context() API in Python, OCaml, and Golang. --- python/t/250-opt-set-meta.py | 126 ++++++++ python/t/255-opt-set-meta-queries.py | 76 +++++ ocaml/tests/Makefile.am | 2 + ocaml/tests/test_250_opt_set_meta.ml | 151 ++++++++++ ocaml/tests/test_255_opt_set_meta_queries.ml | 79 +++++ tests/opt-set-meta-queries.c | 1 + tests/opt-set-meta.c | 1 + golang/Makefile.am | 2 + golang/libnbd_250_opt_set_meta_test.go | 276 ++++++++++++++++++ .../libnbd_255_opt_set_meta_queries_test.go | 141 +++++++++ 10 files changed, 855 insertions(+) create mode 100644 python/t/250-opt-set-meta.py create mode 100644 python/t/255-opt-set-meta-queries.py create mode 100644 ocaml/tests/test_250_opt_set_meta.ml create mode 100644 ocaml/tests/test_255_opt_set_meta_queries.ml create mode 100644 golang/libnbd_250_opt_set_meta_test.go create mode 100644 golang/libnbd_255_opt_set_meta_queries_test.go
diff --git a/python/t/250-opt-set-meta.py b/python/t/250-opt-set-meta.py new file mode 100644 index 00000000..c543a5d6 --- /dev/null +++ b/python/t/250-opt-set-meta.py @@ -0,0 +1,126 @@ +# libnbd Python bindings +# Copyright (C) 2010-2022 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import nbd + + +count = 0 +seen = False + + +def f(user_data, name): + global count + global seen + assert user_data == 42 + count = count + 1 + if name == nbd.CONTEXT_BASE_ALLOCATION: + seen = True + + +def must_fail(f, *args, **kwds): + try: + f(*args, **kwds) + assert False + except nbd.Error: + pass + + +# First process, with structured replies. Get into negotiating state. +h = nbd.NBD() +h.set_opt_mode(True) +h.connect_command(["nbdkit", "-s", "--exit-with-parent", "-v", + "memory", "size=1M"]) + +# No contexts negotiated yet; can_meta should be error if any requested +assert h.get_structured_replies_negotiated() is True +assert h.can_meta_context(nbd.CONTEXT_BASE_ALLOCATION) is False +h.add_meta_context(nbd.CONTEXT_BASE_ALLOCATION) +must_fail(h.can_meta_context, nbd.CONTEXT_BASE_ALLOCATION) + +# FIXME: Once nbd_opt_structured_reply exists, check that set before +# SR fails server-side, then enable SR for rest of process. + +# nbdkit does not match wildcard for SET, even though it does for LIST +count = 0 +seen = False +h.clear_meta_contexts() +h.add_meta_context("base:") +r = h.opt_set_meta_context(lambda *args: f(42, *args)) +assert r == count +assert r == 0 +assert seen is False +assert h.can_meta_context(nbd.CONTEXT_BASE_ALLOCATION) is False + +# Negotiating with no contexts is not an error, but selects nothing +count = 0 +seen = False +h.clear_meta_contexts() +r = h.opt_set_meta_context(lambda *args: f(42, *args)) +assert r == 0 +assert r == count +assert seen is False +assert h.can_meta_context(nbd.CONTEXT_BASE_ALLOCATION) is False + +# Request 2 with expectation of 1; with set_request_meta_context off +count = 0 +seen = False +h.add_meta_context("x-nosuch:context") +h.add_meta_context(nbd.CONTEXT_BASE_ALLOCATION) +h.set_request_meta_context(False) +r = h.opt_set_meta_context(lambda *args: f(42, *args)) +assert r == 1 +assert count == 1 +assert seen is True +assert h.can_meta_context(nbd.CONTEXT_BASE_ALLOCATION) is True + +# Transition to transmission phase; our last set should remain active +h.clear_meta_contexts() +h.add_meta_context("x-nosuch:context") +h.opt_go() +assert h.can_meta_context(nbd.CONTEXT_BASE_ALLOCATION) is True + +# Now too late to set; but should not lose earlier state +count = 0 +seen = False +must_fail(h.opt_set_meta_context, lambda *args: f(42, *args)) +assert count == 0 +assert seen is False +assert h.can_meta_context(nbd.CONTEXT_BASE_ALLOCATION) is True + +h.shutdown() + +# Second process, this time without structured replies server-side. +h = nbd.NBD() +h.set_opt_mode(True) +h.add_meta_context(nbd.CONTEXT_BASE_ALLOCATION) +h.connect_command(["nbdkit", "-s", "--exit-with-parent", "-v", + "memory", "size=1M", "--no-sr"]) +assert h.get_structured_replies_negotiated() is False + +# Expect server-side failure here +count = 0 +seen = False +must_fail(h.opt_set_meta_context, lambda *args: f(42, *args)) +assert count == 0 +assert seen is False +must_fail(h.can_meta_context, nbd.CONTEXT_BASE_ALLOCATION) + +# Even though can_meta fails after failed SET, it returns 0 after go +h.opt_go() +assert h.can_meta_context(nbd.CONTEXT_BASE_ALLOCATION) is False + +h.shutdown() diff --git a/python/t/255-opt-set-meta-queries.py b/python/t/255-opt-set-meta-queries.py new file mode 100644 index 00000000..54a10bc0 --- /dev/null +++ b/python/t/255-opt-set-meta-queries.py @@ -0,0 +1,76 @@ +# libnbd Python bindings +# Copyright (C) 2010-2022 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import nbd + + +count = 0 +seen = False + + +def f(user_data, name): + global count + global seen + assert user_data == 42 + count = count + 1 + if name == nbd.CONTEXT_BASE_ALLOCATION: + seen = True + + +# Get into negotiating state. +h = nbd.NBD() +h.set_opt_mode(True) +h.connect_command(["nbdkit", "-s", "--exit-with-parent", "-v", + "memory", "size=1M"]) + +# nbdkit does not match wildcard for SET, even though it does for LIST +count = 0 +seen = False +r = h.opt_set_meta_context_queries(["base:"], lambda *args: f(42, *args)) +assert r == count +assert r == 0 +assert seen is False +assert h.can_meta_context(nbd.CONTEXT_BASE_ALLOCATION) is False + +# Negotiating with no contexts is not an error, but selects nothing. +# An explicit empty list overrides a non-empty implicit list. +count = 0 +seen = False +h.add_meta_context(nbd.CONTEXT_BASE_ALLOCATION) +r = h.opt_set_meta_context_queries([], lambda *args: f(42, *args)) +assert r == 0 +assert r == count +assert seen is False +assert h.can_meta_context(nbd.CONTEXT_BASE_ALLOCATION) is False + +# Request 2 with expectation of 1. +count = 0 +seen = False +r = h.opt_set_meta_context_queries( + ["x-nosuch:context", nbd.CONTEXT_BASE_ALLOCATION], + lambda *args: f(42, *args)) +assert r == 1 +assert count == 1 +assert seen is True +assert h.can_meta_context(nbd.CONTEXT_BASE_ALLOCATION) is True + +# Transition to transmission phase; our last set should remain active +h.set_request_meta_context(False) +h.opt_go() +assert h.can_meta_context(nbd.CONTEXT_BASE_ALLOCATION) is True + +h.shutdown() diff --git a/ocaml/tests/Makefile.am b/ocaml/tests/Makefile.am index 1b4d1135..328d53e5 100644 --- a/ocaml/tests/Makefile.am +++ b/ocaml/tests/Makefile.am @@ -32,6 +32,8 @@ ML_TESTS = \ test_230_opt_info.ml \ test_240_opt_list_meta.ml \ test_245_opt_list_meta_queries.ml \ + test_250_opt_set_meta.ml \ + test_255_opt_set_meta_queries.ml \ test_300_get_size.ml \ test_400_pread.ml \ test_405_pread_structured.ml \ diff --git a/ocaml/tests/test_250_opt_set_meta.ml b/ocaml/tests/test_250_opt_set_meta.ml new file mode 100644 index 00000000..f35012fd --- /dev/null +++ b/ocaml/tests/test_250_opt_set_meta.ml @@ -0,0 +1,151 @@ +(* hey emacs, this is OCaml code: -*- tuareg -*- *) +(* libnbd OCaml test case + * Copyright (C) 2013-2022 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +let count = ref 0 +let seen = ref false +let f user_data name = + assert (user_data = 42); + count := !count + 1; + if name = NBD.context_base_allocation then + seen := true; + 0 + +let () = + (* First process, with structured replies. Get into negotiating state. *) + let nbd = NBD.create () in + NBD.set_opt_mode nbd true; + NBD.connect_command nbd + ["nbdkit"; "-s"; "--exit-with-parent"; "-v"; + "memory"; "size=1M"]; + + (* No contexts negotiated yet; can_meta should be error if any requested *) + let sr = NBD.get_structured_replies_negotiated nbd in + assert sr; + let m = NBD.can_meta_context nbd NBD.context_base_allocation in + assert (not m); + NBD.add_meta_context nbd NBD.context_base_allocation; + (try + let _ = NBD.can_meta_context nbd NBD.context_base_allocation in + assert false + with + NBD.Error (errstr, errno) -> () + ); + + (* FIXME: Once nbd_opt_structured_reply exists, check that set before + * SR fails server-side, then enable SR for rest of process. + *) + + (* nbdkit does not match wildcard for SET, even though it does for LIST *) + count := 0; + seen := false; + NBD.clear_meta_contexts nbd; + NBD.add_meta_context nbd "base:"; + let r = NBD.opt_set_meta_context nbd (f 42) in + assert (r = !count); + assert (r = 0); + assert (not !seen); + let m = NBD.can_meta_context nbd NBD.context_base_allocation in + assert (not m); + + (* Negotiating with no contexts is not an error, but selects nothing *) + count := 0; + seen := false; + NBD.clear_meta_contexts nbd; + let r = NBD.opt_set_meta_context nbd (f 42) in + assert (r = 0); + assert (r = !count); + assert (not !seen); + let m = NBD.can_meta_context nbd NBD.context_base_allocation in + assert (not m); + + (* Request 2 with expectation of 1; with set_request_meta_context off *) + count := 0; + seen := false; + NBD.add_meta_context nbd "x-nosuch:context"; + NBD.add_meta_context nbd NBD.context_base_allocation; + NBD.set_request_meta_context nbd false; + let r = NBD.opt_set_meta_context nbd (f 42) in + assert (r = 1); + assert (r = !count); + assert !seen; + let m = NBD.can_meta_context nbd NBD.context_base_allocation in + assert m; + + (* Transition to transmission phase; our last set should remain active *) + NBD.clear_meta_contexts nbd; + NBD.add_meta_context nbd "x-nosuch:context"; + NBD.opt_go nbd; + let m = NBD.can_meta_context nbd NBD.context_base_allocation in + assert m; + + (* Now too late to set; but should not lose earlier state *) + count := 0; + seen := false; + (try + let _ = NBD.opt_set_meta_context nbd (f 42) in + assert false + with + NBD.Error (errstr, errno) -> () + ); + assert (0 = !count); + assert (not !seen); + let s = NBD.get_size nbd in + assert (s = 1048576_L); + let m = NBD.can_meta_context nbd NBD.context_base_allocation in + assert m; + + NBD.shutdown nbd; + + (* Second process, this time without structured replies server-side. *) + let nbd = NBD.create () in + NBD.set_opt_mode nbd true; + NBD.add_meta_context nbd NBD.context_base_allocation; + NBD.connect_command nbd + ["nbdkit"; "-s"; "--exit-with-parent"; "-v"; + "memory"; "size=1M"; "--no-sr"]; + let sr = NBD.get_structured_replies_negotiated nbd in + assert (not sr); + + (* Expect server-side failure here *) + count := 0; + seen := false; + NBD.add_meta_context nbd "base:"; + (try + let _ = NBD.opt_set_meta_context nbd (f 42) in + assert false + with + NBD.Error (errstr, errno) -> () + ); + assert (0 = !count); + assert (not !seen); + (try + let _ = NBD.can_meta_context nbd NBD.context_base_allocation in + assert false + with + NBD.Error (errstr, errno) -> () + ); + + (* Even though can_meta fails after failed SET, it returns 0 after go *) + NBD.opt_go nbd; + let m = NBD.can_meta_context nbd NBD.context_base_allocation in + assert (not m); + + NBD.shutdown nbd + +let () = Gc.compact () diff --git a/ocaml/tests/test_255_opt_set_meta_queries.ml b/ocaml/tests/test_255_opt_set_meta_queries.ml new file mode 100644 index 00000000..86e27e1f --- /dev/null +++ b/ocaml/tests/test_255_opt_set_meta_queries.ml @@ -0,0 +1,79 @@ +(* hey emacs, this is OCaml code: -*- tuareg -*- *) +(* libnbd OCaml test case + * Copyright (C) 2013-2022 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +let count = ref 0 +let seen = ref false +let f user_data name = + assert (user_data = 42); + count := !count + 1; + if name = NBD.context_base_allocation then + seen := true; + 0 + +let () = + (* Get into negotiating state. *) + let nbd = NBD.create () in + NBD.set_opt_mode nbd true; + NBD.connect_command nbd + ["nbdkit"; "-s"; "--exit-with-parent"; "-v"; + "memory"; "size=1M"]; + + (* nbdkit does not match wildcard for SET, even though it does for LIST *) + count := 0; + seen := false; + let r = NBD.opt_set_meta_context_queries nbd ["base:"] (f 42) in + assert (r = !count); + assert (r = 0); + assert (not !seen); + let m = NBD.can_meta_context nbd NBD.context_base_allocation in + assert (not m); + + (* Negotiating with no contexts is not an error, but selects nothing. + * An explicit empty list overrides a non-empty implicit list. + *) + count := 0; + seen := false; + NBD.add_meta_context nbd NBD.context_base_allocation; + let r = NBD.opt_set_meta_context_queries nbd [] (f 42) in + assert (r = 0); + assert (r = !count); + assert (not !seen); + let m = NBD.can_meta_context nbd NBD.context_base_allocation in + assert (not m); + + (* Request 2 with expectation of 1. *) + count := 0; + seen := false; + let r = NBD.opt_set_meta_context_queries nbd + ["x-nosuch:context"; NBD.context_base_allocation] (f 42) in + assert (r = 1); + assert (r = !count); + assert !seen; + let m = NBD.can_meta_context nbd NBD.context_base_allocation in + assert m; + + (* Transition to transmission phase; our last set should remain active *) + NBD.set_request_meta_context nbd false; + NBD.opt_go nbd; + let m = NBD.can_meta_context nbd NBD.context_base_allocation in + assert m; + + NBD.shutdown nbd + +let () = Gc.compact () diff --git a/tests/opt-set-meta-queries.c b/tests/opt-set-meta-queries.c index 0b162607..2c3ee29a 100644 --- a/tests/opt-set-meta-queries.c +++ b/tests/opt-set-meta-queries.c @@ -17,6 +17,7 @@ */ /* Test behavior of nbd_opt_set_meta_context_queries. */ +/* See also unit test 255 in the various language ports. */ #include <config.h> diff --git a/tests/opt-set-meta.c b/tests/opt-set-meta.c index 95f5a6d7..a4366d24 100644 --- a/tests/opt-set-meta.c +++ b/tests/opt-set-meta.c @@ -17,6 +17,7 @@ */ /* Test behavior of nbd_opt_set_meta_context. */ +/* See also unit test 250 in the various language ports. */ #include <config.h> diff --git a/golang/Makefile.am b/golang/Makefile.am index 6adf6ae8..0808a639 100644 --- a/golang/Makefile.am +++ b/golang/Makefile.am @@ -36,6 +36,8 @@ source_files = \ libnbd_230_opt_info_test.go \ libnbd_240_opt_list_meta_test.go \ libnbd_245_opt_list_meta_queries_test.go \ + libnbd_250_opt_set_meta_test.go \ + libnbd_255_opt_set_meta_queries_test.go \ libnbd_300_get_size_test.go \ libnbd_400_pread_test.go \ libnbd_405_pread_structured_test.go \ diff --git a/golang/libnbd_250_opt_set_meta_test.go b/golang/libnbd_250_opt_set_meta_test.go new file mode 100644 index 00000000..1740d83e --- /dev/null +++ b/golang/libnbd_250_opt_set_meta_test.go @@ -0,0 +1,276 @@ +/* libnbd golang tests + * Copyright (C) 2013-2022 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package libnbd + +import "testing" + +var set_count uint +var set_seen bool + +func setmetaf(user_data int, name string) int { + if user_data != 42 { + panic("expected user_data == 42") + } + set_count++ + if (name == context_base_allocation) { + set_seen = true + } + return 0 +} + +func Test250OptSetMeta(t *testing.T) { + /* First process, with structured replies. Get into negotiating state. */ + h, err := Create() + if err != nil { + t.Fatalf("could not create handle: %s", err) + } + defer h.Close() + + err = h.SetOptMode(true) + if err != nil { + t.Fatalf("could not set opt mode: %s", err) + } + + err = h.ConnectCommand([]string{ + "nbdkit", "-s", "--exit-with-parent", "-v", + "memory", "size=1M", + }) + if err != nil { + t.Fatalf("could not connect: %s", err) + } + + /* No contexts negotiated yet; CanMeta should be error if any requested */ + sr, err := h.GetStructuredRepliesNegotiated() + if err != nil { + t.Fatalf("could not check structured replies negotiated: %s", err) + } + if !sr { + t.Fatalf("unexpected structured replies state") + } + meta, err := h.CanMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not check can meta context: %s", err) + } + if meta { + t.Fatalf("unexpected can meta context state") + } + err = h.AddMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not request add_meta_context: %s", err) + } + _, err = h.CanMetaContext(context_base_allocation) + if err == nil { + t.Fatalf("expected error") + } + + /* FIXME: Once OptStructuredReply exists, check that set before + * SR fails server-side, then enable SR for rest of process. + */ + + /* nbdkit does not match wildcard for SET, even though it does for LIST */ + set_count = 0 + set_seen = false + err = h.ClearMetaContexts() + if err != nil { + t.Fatalf("could not request clear_meta_contexts: %s", err) + } + err = h.AddMetaContext("base:") + if err != nil { + t.Fatalf("could not request add_meta_context: %s", err) + } + r, err := h.OptSetMetaContext(func(name string) int { + return setmetaf(42, name) + }) + if err != nil { + t.Fatalf("could not request opt_set_meta_context: %s", err) + } + if r != set_count || r != 0 || set_seen { + t.Fatalf("unexpected set_count after opt_set_meta_context") + } + + /* Negotiating with no contexts is not an error, but selects nothing */ + set_count = 0 + set_seen = false + err = h.ClearMetaContexts() + if err != nil { + t.Fatalf("could not request clear_meta_contexts: %s", err) + } + r, err = h.OptSetMetaContext(func(name string) int { + return setmetaf(42, name) + }) + if err != nil { + t.Fatalf("could not request opt_set_meta_context: %s", err) + } + if r != set_count || r != 0 || set_seen { + t.Fatalf("unexpected set_count after opt_set_meta_context") + } + meta, err = h.CanMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not check can meta context: %s", err) + } + if meta { + t.Fatalf("unexpected can meta context state") + } + + /* Request 2 with expectation of 1; with SetRequestMetaContext off */ + set_count = 0 + set_seen = false + err = h.AddMetaContext("x-nosuch:context") + if err != nil { + t.Fatalf("could not request add_meta_context: %s", err) + } + err = h.AddMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not request add_meta_context: %s", err) + } + err = h.SetRequestMetaContext(false) + if err != nil { + t.Fatalf("could not set_request_meta_context: %s", err) + } + r, err = h.OptSetMetaContext(func(name string) int { + return setmetaf(42, name) + }) + if err != nil { + t.Fatalf("could not request opt_set_meta_context: %s", err) + } + if r != 1 || r != set_count || !set_seen { + t.Fatalf("unexpected set_count after opt_set_meta_context") + } + meta, err = h.CanMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not check can meta context: %s", err) + } + if !meta { + t.Fatalf("unexpected can meta context state") + } + + /* Transition to transmission phase; our last set should remain active */ + err = h.ClearMetaContexts() + if err != nil { + t.Fatalf("could not request clear_meta_contexts: %s", err) + } + err = h.AddMetaContext("x-nosuch:context") + if err != nil { + t.Fatalf("could not request add_meta_context: %s", err) + } + err = h.OptGo() + if err != nil { + t.Fatalf("could not request opt_go: %s", err) + } + meta, err = h.CanMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not check can meta context: %s", err) + } + if !meta { + t.Fatalf("unexpected can meta context state") + } + + /* Now too late to set; but should not lose earlier state */ + set_count = 0 + set_seen = false + _, err = h.OptSetMetaContext(func(name string) int { + return setmetaf(42, name) + }) + if err == nil { + t.Fatalf("expected error") + } + if set_count != 0 || set_seen { + t.Fatalf("unexpected set_count after opt_set_meta_context") + } + meta, err = h.CanMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not check can meta context: %s", err) + } + if !meta { + t.Fatalf("unexpected can meta context state") + } + + err = h.Shutdown(nil) + if err != nil { + t.Fatalf("could not request shutdown: %s", err) + } + + /* Second process, this time without structured replies server-side. */ + h, err = Create() + if err != nil { + t.Fatalf("could not create handle: %s", err) + } + defer h.Close() + + err = h.SetOptMode(true) + if err != nil { + t.Fatalf("could not set opt mode: %s", err) + } + + err = h.AddMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not request add_meta_context: %s", err) + } + + err = h.ConnectCommand([]string{ + "nbdkit", "-s", "--exit-with-parent", "-v", + "memory", "size=1M", "--no-sr", + }) + if err != nil { + t.Fatalf("could not connect: %s", err) + } + + sr, err = h.GetStructuredRepliesNegotiated() + if err != nil { + t.Fatalf("could not check structured replies negotiated: %s", err) + } + if sr { + t.Fatalf("unexpected structured replies state") + } + + /* Expect server-side failure here */ + set_count = 0 + set_seen = false + _, err = h.OptSetMetaContext(func(name string) int { + return setmetaf(42, name) + }) + if err == nil { + t.Fatalf("expected error") + } + if set_count != 0 || set_seen { + t.Fatalf("unexpected set_count after opt_set_meta_context") + } + _, err = h.CanMetaContext(context_base_allocation) + if err == nil { + t.Fatalf("expected error") + } + + /* Even though CanMeta fails after failed SET, it returns 0 after go */ + err = h.OptGo() + if err != nil { + t.Fatalf("could not request opt_go: %s", err) + } + meta, err = h.CanMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not check can meta context: %s", err) + } + if meta { + t.Fatalf("unexpected can meta context state") + } + + err = h.Shutdown(nil) + if err != nil { + t.Fatalf("could not request shutdown: %s", err) + } +} diff --git a/golang/libnbd_255_opt_set_meta_queries_test.go b/golang/libnbd_255_opt_set_meta_queries_test.go new file mode 100644 index 00000000..96b37d76 --- /dev/null +++ b/golang/libnbd_255_opt_set_meta_queries_test.go @@ -0,0 +1,141 @@ +/* libnbd golang tests + * Copyright (C) 2013-2022 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package libnbd + +import "testing" + +var setq_count uint +var setq_seen bool + +func setmetaqf(user_data int, name string) int { + if user_data != 42 { + panic("expected user_data == 42") + } + setq_count++ + if (name == context_base_allocation) { + setq_seen = true + } + return 0 +} + +func Test255OptSetMetaQueries(t *testing.T) { + /* Get into negotiating state. */ + h, err := Create() + if err != nil { + t.Fatalf("could not create handle: %s", err) + } + defer h.Close() + + err = h.SetOptMode(true) + if err != nil { + t.Fatalf("could not set opt mode: %s", err) + } + + err = h.ConnectCommand([]string{ + "nbdkit", "-s", "--exit-with-parent", "-v", + "memory", "size=1M", + }) + if err != nil { + t.Fatalf("could not connect: %s", err) + } + + /* nbdkit does not match wildcard for SET, even though it does for LIST */ + setq_count = 0 + setq_seen = false + r, err := h.OptSetMetaContextQueries([]string{"base:"}, + func(name string) int { + return setmetaqf(42, name) + }) + if err != nil { + t.Fatalf("could not request opt_set_meta_context_queries: %s", err) + } + if r != setq_count || r != 0 || setq_seen { + t.Fatalf("unexpected count after opt_set_meta_context_queries") + } + + /* Negotiating with no contexts is not an error, but selects nothing. + * An explicit empty list overrides a non-empty implicit list. + */ + setq_count = 0 + setq_seen = false + err = h.AddMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not request add_meta_context: %s", err) + } + r, err = h.OptSetMetaContextQueries([]string{}, func(name string) int { + return setmetaqf(42, name) + }) + if err != nil { + t.Fatalf("could not request opt_set_meta_context_queries: %s", err) + } + if r != setq_count || r != 0 || setq_seen { + t.Fatalf("unexpected set_count after opt_set_meta_context_queries") + } + meta, err := h.CanMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not check can meta context: %s", err) + } + if meta { + t.Fatalf("unexpected can meta context state") + } + + /* Request 2 with expectation of 1; with SetRequestMetaContext off */ + setq_count = 0 + setq_seen = false + r, err = h.OptSetMetaContextQueries([]string{ + "x-nosuch:context", context_base_allocation}, + func(name string) int { + return setmetaqf(42, name) + }) + if err != nil { + t.Fatalf("could not request opt_set_meta_context_queries: %s", err) + } + if r != 1 || r != setq_count || !setq_seen { + t.Fatalf("unexpected set_count after opt_set_meta_context_queries") + } + meta, err = h.CanMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not check can meta context: %s", err) + } + if !meta { + t.Fatalf("unexpected can meta context state") + } + + /* Transition to transmission phase; our last set should remain active */ + err = h.SetRequestMetaContext(false) + if err != nil { + t.Fatalf("could not set_request_meta_context: %s", err) + } + err = h.OptGo() + if err != nil { + t.Fatalf("could not request opt_go: %s", err) + } + meta, err = h.CanMetaContext(context_base_allocation) + if err != nil { + t.Fatalf("could not check can meta context: %s", err) + } + if !meta { + t.Fatalf("unexpected can meta context state") + } + + err = h.Shutdown(nil) + if err != nil { + t.Fatalf("could not request shutdown: %s", err) + } +} -- 2.37.3 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://listman.redhat.com/mailman/listinfo/libguestfs