Eric Blake
2022-Aug-31 14:39 UTC
[Libguestfs] [libnbd PATCH v2 12/12] tests: Language port of nbd_opt_set_meta_context() tests
As promised in the previous patch, also test the new
nbd_opt_set_meta_context() API in Python, OCaml, and Golang.
The fact that Go slams all unit tests into the same namespace is
somewhat annoying; it required munging test 240 now that 250 wants to
use similar global variables.
---
python/t/250-opt-set-meta.py | 126 ++++++++++++
ocaml/tests/Makefile.am | 5 +-
ocaml/tests/test_250_opt_set_meta.ml | 150 ++++++++++++++
tests/opt-set-meta.c | 1 +
golang/Makefile.am | 3 +-
golang/libnbd_240_opt_list_meta_test.go | 54 +++---
golang/libnbd_250_opt_set_meta_test.go | 248 ++++++++++++++++++++++++
7 files changed, 558 insertions(+), 29 deletions(-)
create mode 100644 python/t/250-opt-set-meta.py
create mode 100644 ocaml/tests/test_250_opt_set_meta.ml
create mode 100644 golang/libnbd_250_opt_set_meta_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 0000000..eb27998
--- /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 not seen
+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 not seen
+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
+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 not seen
+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 not seen
+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/ocaml/tests/Makefile.am b/ocaml/tests/Makefile.am
index 24f626d..f8ce810 100644
--- a/ocaml/tests/Makefile.am
+++ b/ocaml/tests/Makefile.am
@@ -1,5 +1,5 @@
# nbd client library in userspace
-# Copyright (C) 2013-2020 Red Hat Inc.
+# 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
@@ -31,6 +31,7 @@ EXTRA_DIST = \
test_220_opt_list.ml \
test_230_opt_info.ml \
test_240_opt_list_meta.ml \
+ test_250_opt_set_meta.ml \
test_300_get_size.ml \
test_400_pread.ml \
test_405_pread_structured.ml \
@@ -59,6 +60,7 @@ tests_bc = \
test_220_opt_list.bc \
test_230_opt_info.bc \
test_240_opt_list_meta.bc \
+ test_250_opt_set_meta.bc \
test_300_get_size.bc \
test_400_pread.bc \
test_405_pread_structured.bc \
@@ -84,6 +86,7 @@ tests_opt = \
test_220_opt_list.opt \
test_230_opt_info.opt \
test_240_opt_list_meta.opt \
+ test_250_opt_set_meta.opt \
test_300_get_size.opt \
test_400_pread.opt \
test_405_pread_structured.opt \
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 0000000..d74e9e0
--- /dev/null
+++ b/ocaml/tests/test_250_opt_set_meta.ml
@@ -0,0 +1,150 @@
+(* 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 () + 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/tests/opt-set-meta.c b/tests/opt-set-meta.c
index 01c9604..bd00276 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 f170cbc..f6e6f91 100644
--- a/golang/Makefile.am
+++ b/golang/Makefile.am
@@ -1,5 +1,5 @@
# nbd client library in userspace
-# Copyright (C) 2013-2020 Red Hat Inc.
+# 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
@@ -35,6 +35,7 @@ source_files = \
libnbd_220_opt_list_test.go \
libnbd_230_opt_info_test.go \
libnbd_240_opt_list_meta_test.go \
+ libnbd_250_opt_set_meta_test.go \
libnbd_300_get_size_test.go \
libnbd_400_pread_test.go \
libnbd_405_pread_structured_test.go \
diff --git a/golang/libnbd_240_opt_list_meta_test.go
b/golang/libnbd_240_opt_list_meta_test.go
index 47df787..4af1008 100644
--- a/golang/libnbd_240_opt_list_meta_test.go
+++ b/golang/libnbd_240_opt_list_meta_test.go
@@ -22,16 +22,16 @@ import (
"testing"
)
-var count uint
-var seen bool
+var list_count uint
+var list_seen bool
func listmetaf(user_data int, name string) int {
if user_data != 42 {
panic("expected user_data == 42")
}
- count++
+ list_count++
if (name == context_base_allocation) {
- seen = true
+ list_seen = true
}
return 0
}
@@ -57,22 +57,22 @@ func Test240OptListMeta(t *testing.T) {
}
/* First pass: empty query should give at least "base:allocation".
*/
- count = 0
- seen = false
+ list_count = 0
+ list_seen = false
r, err := h.OptListMetaContext(func(name string) int {
return listmetaf(42, name)
})
if err != nil {
t.Fatalf("could not request opt_list_meta_context: %s", err)
}
- if r != count || r < 1 || !seen {
- t.Fatalf("unexpected count after opt_list_meta_context")
+ if r != list_count || r < 1 || !list_seen {
+ t.Fatalf("unexpected list_count after opt_list_meta_context")
}
- max := count
+ max := list_count
/* Second pass: bogus query has no response. */
- count = 0
- seen = false
+ list_count = 0
+ list_seen = false
err = h.AddMetaContext("x-nosuch:")
if err != nil {
t.Fatalf("could not request add_meta_context: %s", err)
@@ -83,13 +83,13 @@ func Test240OptListMeta(t *testing.T) {
if err != nil {
t.Fatalf("could not request opt_list_meta_context: %s", err)
}
- if r != 0 || r != count || seen {
- t.Fatalf("unexpected count after opt_list_meta_context")
+ if r != 0 || r != list_count || list_seen {
+ t.Fatalf("unexpected list_count after opt_list_meta_context")
}
/* Third pass: specific query should have one match. */
- count = 0
- seen = false
+ list_count = 0
+ list_seen = false
err = h.AddMetaContext(context_base_allocation)
if err != nil {
t.Fatalf("could not request add_meta_context: %s", err)
@@ -114,15 +114,15 @@ func Test240OptListMeta(t *testing.T) {
if err != nil {
t.Fatalf("could not request opt_list_meta_context: %s", err)
}
- if r != 1 || r != count || !seen {
- t.Fatalf("unexpected count after opt_list_meta_context")
+ if r != 1 || r != list_count || !list_seen {
+ t.Fatalf("unexpected list_count after opt_list_meta_context")
}
/* Fourth pass: opt_list_meta_context is stateless, so it should
* not wipe status learned during opt_info
*/
- count = 0
- seen = false
+ list_count = 0
+ list_seen = false
_, err = h.GetSize()
if err == nil {
t.Fatalf("expected error")
@@ -147,7 +147,7 @@ func Test240OptListMeta(t *testing.T) {
t.Fatalf("can_meta_context failed unexpectedly: %s", err)
}
if !meta {
- t.Fatalf("unexpected count after can_meta_context")
+ t.Fatalf("unexpected list_count after can_meta_context")
}
err = h.ClearMetaContexts()
if err != nil {
@@ -163,8 +163,8 @@ func Test240OptListMeta(t *testing.T) {
if err != nil {
t.Fatalf("could not request opt_list_meta_context: %s", err)
}
- if r != 0 || r != count || seen {
- t.Fatalf("unexpected count after opt_list_meta_context")
+ if r != 0 || r != list_count || list_seen {
+ t.Fatalf("unexpected list_count after opt_list_meta_context")
}
size, err = h.GetSize()
if err != nil {
@@ -178,13 +178,13 @@ func Test240OptListMeta(t *testing.T) {
t.Fatalf("can_meta_context failed unexpectedly: %s", err)
}
if !meta {
- t.Fatalf("unexpected count after can_meta_context")
+ t.Fatalf("unexpected list_count after can_meta_context")
}
err = h.ClearMetaContexts()
/* Final pass: "base:" query should get at least
"base:allocation" */
- count = 0
- seen = false
+ list_count = 0
+ list_seen = false
err = h.AddMetaContext("base:")
if err != nil {
t.Fatalf("could not request add_meta_context: %s", err)
@@ -195,8 +195,8 @@ func Test240OptListMeta(t *testing.T) {
if err != nil {
t.Fatalf("could not request opt_list_meta_context: %s", err)
}
- if r < 1 || r > max || r != count || !seen {
- t.Fatalf("unexpected count after opt_list_meta_context")
+ if r < 1 || r > max || r != list_count || !list_seen {
+ t.Fatalf("unexpected list_count after opt_list_meta_context")
}
err = h.OptAbort()
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 0000000..c29b7f4
--- /dev/null
+++ b/golang/libnbd_250_opt_set_meta_test.go
@@ -0,0 +1,248 @@
+/* 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) {
+ 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")
+ }
+
+ /* 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")
+ }
+}
--
2.37.2
Laszlo Ersek
2022-Sep-01 07:53 UTC
[Libguestfs] [libnbd PATCH v2 12/12] tests: Language port of nbd_opt_set_meta_context() tests
On 08/31/22 16:39, Eric Blake wrote:> As promised in the previous patch, also test the new > nbd_opt_set_meta_context() API in Python, OCaml, and Golang. > > The fact that Go slams all unit tests into the same namespace is > somewhat annoying; it required munging test 240 now that 250 wants to > use similar global variables. > --- > python/t/250-opt-set-meta.py | 126 ++++++++++++ > ocaml/tests/Makefile.am | 5 +- > ocaml/tests/test_250_opt_set_meta.ml | 150 ++++++++++++++ > tests/opt-set-meta.c | 1 + > golang/Makefile.am | 3 +- > golang/libnbd_240_opt_list_meta_test.go | 54 +++--- > golang/libnbd_250_opt_set_meta_test.go | 248 ++++++++++++++++++++++++ > 7 files changed, 558 insertions(+), 29 deletions(-) > create mode 100644 python/t/250-opt-set-meta.py > create mode 100644 ocaml/tests/test_250_opt_set_meta.ml > create mode 100644 golang/libnbd_250_opt_set_meta_test.gogit-am reports the following whitespace errors on this patch: .git/rebase-apply/patch:579: space before tab in indent. t.Fatalf("unexpected structured replies state") .git/rebase-apply/patch:586: space before tab in indent. t.Fatalf("unexpected can meta context state") .git/rebase-apply/patch:651: space before tab in indent. t.Fatalf("unexpected can meta context state") .git/rebase-apply/patch:672: space before tab in indent. t.Fatalf("unexpected can meta context state") .git/rebase-apply/patch:692: space before tab in indent. t.Fatalf("unexpected can meta context state") warning: squelched 2 whitespace errors warning: 7 lines add whitespace errors. Laszlo
Laszlo Ersek
2022-Sep-09 07:10 UTC
[Libguestfs] [libnbd PATCH v2 12/12] tests: Language port of nbd_opt_set_meta_context() tests
On 08/31/22 16:39, Eric Blake wrote:> As promised in the previous patch, also test the new > nbd_opt_set_meta_context() API in Python, OCaml, and Golang. > > The fact that Go slams all unit tests into the same namespace is > somewhat annoying; it required munging test 240 now that 250 wants to > use similar global variables. > --- > python/t/250-opt-set-meta.py | 126 ++++++++++++ > ocaml/tests/Makefile.am | 5 +- > ocaml/tests/test_250_opt_set_meta.ml | 150 ++++++++++++++ > tests/opt-set-meta.c | 1 + > golang/Makefile.am | 3 +- > golang/libnbd_240_opt_list_meta_test.go | 54 +++--- > golang/libnbd_250_opt_set_meta_test.go | 248 ++++++++++++++++++++++++ > 7 files changed, 558 insertions(+), 29 deletions(-) > create mode 100644 python/t/250-opt-set-meta.py > create mode 100644 ocaml/tests/test_250_opt_set_meta.ml > create mode 100644 golang/libnbd_250_opt_set_meta_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 0000000..eb27998 > --- /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 */I think the "*/" at the end of the line may be a remnant from the C code.> +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)(I had to re-read the docs on can_meta_context.) Non-intuitive, but valid, as far as I can tell.> + > +# 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 not seen > +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 not seen > +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 > +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 not seen > +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 not seen > +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()Acked-by: Laszlo Ersek <lersek at redhat.com> Laszlo> diff --git a/ocaml/tests/Makefile.am b/ocaml/tests/Makefile.am > index 24f626d..f8ce810 100644 > --- a/ocaml/tests/Makefile.am > +++ b/ocaml/tests/Makefile.am > @@ -1,5 +1,5 @@ > # nbd client library in userspace > -# Copyright (C) 2013-2020 Red Hat Inc. > +# 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 > @@ -31,6 +31,7 @@ EXTRA_DIST = \ > test_220_opt_list.ml \ > test_230_opt_info.ml \ > test_240_opt_list_meta.ml \ > + test_250_opt_set_meta.ml \ > test_300_get_size.ml \ > test_400_pread.ml \ > test_405_pread_structured.ml \ > @@ -59,6 +60,7 @@ tests_bc = \ > test_220_opt_list.bc \ > test_230_opt_info.bc \ > test_240_opt_list_meta.bc \ > + test_250_opt_set_meta.bc \ > test_300_get_size.bc \ > test_400_pread.bc \ > test_405_pread_structured.bc \ > @@ -84,6 +86,7 @@ tests_opt = \ > test_220_opt_list.opt \ > test_230_opt_info.opt \ > test_240_opt_list_meta.opt \ > + test_250_opt_set_meta.opt \ > test_300_get_size.opt \ > test_400_pread.opt \ > test_405_pread_structured.opt \ > 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 0000000..d74e9e0 > --- /dev/null > +++ b/ocaml/tests/test_250_opt_set_meta.ml > @@ -0,0 +1,150 @@ > +(* 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 () > + 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/tests/opt-set-meta.c b/tests/opt-set-meta.c > index 01c9604..bd00276 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 f170cbc..f6e6f91 100644 > --- a/golang/Makefile.am > +++ b/golang/Makefile.am > @@ -1,5 +1,5 @@ > # nbd client library in userspace > -# Copyright (C) 2013-2020 Red Hat Inc. > +# 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 > @@ -35,6 +35,7 @@ source_files = \ > libnbd_220_opt_list_test.go \ > libnbd_230_opt_info_test.go \ > libnbd_240_opt_list_meta_test.go \ > + libnbd_250_opt_set_meta_test.go \ > libnbd_300_get_size_test.go \ > libnbd_400_pread_test.go \ > libnbd_405_pread_structured_test.go \ > diff --git a/golang/libnbd_240_opt_list_meta_test.go b/golang/libnbd_240_opt_list_meta_test.go > index 47df787..4af1008 100644 > --- a/golang/libnbd_240_opt_list_meta_test.go > +++ b/golang/libnbd_240_opt_list_meta_test.go > @@ -22,16 +22,16 @@ import ( > "testing" > ) > > -var count uint > -var seen bool > +var list_count uint > +var list_seen bool > > func listmetaf(user_data int, name string) int { > if user_data != 42 { > panic("expected user_data == 42") > } > - count++ > + list_count++ > if (name == context_base_allocation) { > - seen = true > + list_seen = true > } > return 0 > } > @@ -57,22 +57,22 @@ func Test240OptListMeta(t *testing.T) { > } > > /* First pass: empty query should give at least "base:allocation". */ > - count = 0 > - seen = false > + list_count = 0 > + list_seen = false > r, err := h.OptListMetaContext(func(name string) int { > return listmetaf(42, name) > }) > if err != nil { > t.Fatalf("could not request opt_list_meta_context: %s", err) > } > - if r != count || r < 1 || !seen { > - t.Fatalf("unexpected count after opt_list_meta_context") > + if r != list_count || r < 1 || !list_seen { > + t.Fatalf("unexpected list_count after opt_list_meta_context") > } > - max := count > + max := list_count > > /* Second pass: bogus query has no response. */ > - count = 0 > - seen = false > + list_count = 0 > + list_seen = false > err = h.AddMetaContext("x-nosuch:") > if err != nil { > t.Fatalf("could not request add_meta_context: %s", err) > @@ -83,13 +83,13 @@ func Test240OptListMeta(t *testing.T) { > if err != nil { > t.Fatalf("could not request opt_list_meta_context: %s", err) > } > - if r != 0 || r != count || seen { > - t.Fatalf("unexpected count after opt_list_meta_context") > + if r != 0 || r != list_count || list_seen { > + t.Fatalf("unexpected list_count after opt_list_meta_context") > } > > /* Third pass: specific query should have one match. */ > - count = 0 > - seen = false > + list_count = 0 > + list_seen = false > err = h.AddMetaContext(context_base_allocation) > if err != nil { > t.Fatalf("could not request add_meta_context: %s", err) > @@ -114,15 +114,15 @@ func Test240OptListMeta(t *testing.T) { > if err != nil { > t.Fatalf("could not request opt_list_meta_context: %s", err) > } > - if r != 1 || r != count || !seen { > - t.Fatalf("unexpected count after opt_list_meta_context") > + if r != 1 || r != list_count || !list_seen { > + t.Fatalf("unexpected list_count after opt_list_meta_context") > } > > /* Fourth pass: opt_list_meta_context is stateless, so it should > * not wipe status learned during opt_info > */ > - count = 0 > - seen = false > + list_count = 0 > + list_seen = false > _, err = h.GetSize() > if err == nil { > t.Fatalf("expected error") > @@ -147,7 +147,7 @@ func Test240OptListMeta(t *testing.T) { > t.Fatalf("can_meta_context failed unexpectedly: %s", err) > } > if !meta { > - t.Fatalf("unexpected count after can_meta_context") > + t.Fatalf("unexpected list_count after can_meta_context") > } > err = h.ClearMetaContexts() > if err != nil { > @@ -163,8 +163,8 @@ func Test240OptListMeta(t *testing.T) { > if err != nil { > t.Fatalf("could not request opt_list_meta_context: %s", err) > } > - if r != 0 || r != count || seen { > - t.Fatalf("unexpected count after opt_list_meta_context") > + if r != 0 || r != list_count || list_seen { > + t.Fatalf("unexpected list_count after opt_list_meta_context") > } > size, err = h.GetSize() > if err != nil { > @@ -178,13 +178,13 @@ func Test240OptListMeta(t *testing.T) { > t.Fatalf("can_meta_context failed unexpectedly: %s", err) > } > if !meta { > - t.Fatalf("unexpected count after can_meta_context") > + t.Fatalf("unexpected list_count after can_meta_context") > } > err = h.ClearMetaContexts() > > /* Final pass: "base:" query should get at least "base:allocation" */ > - count = 0 > - seen = false > + list_count = 0 > + list_seen = false > err = h.AddMetaContext("base:") > if err != nil { > t.Fatalf("could not request add_meta_context: %s", err) > @@ -195,8 +195,8 @@ func Test240OptListMeta(t *testing.T) { > if err != nil { > t.Fatalf("could not request opt_list_meta_context: %s", err) > } > - if r < 1 || r > max || r != count || !seen { > - t.Fatalf("unexpected count after opt_list_meta_context") > + if r < 1 || r > max || r != list_count || !list_seen { > + t.Fatalf("unexpected list_count after opt_list_meta_context") > } > > err = h.OptAbort() > 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 0000000..c29b7f4 > --- /dev/null > +++ b/golang/libnbd_250_opt_set_meta_test.go > @@ -0,0 +1,248 @@ > +/* 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) { > + 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") > + } > + > + /* 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") > + } > +} >