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 <ler...@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")
> +        }
> +}
> 

_______________________________________________
Libguestfs mailing list
Libguestfs@redhat.com
https://listman.redhat.com/mailman/listinfo/libguestfs

Reply via email to