This proves that the stat counters increment as desired, as well as
proving that our RUInt32 generator type works.

This commit is also a showcase of whether I can do 64-bit math in
various languages (C's terseness in 'a == b + (c > d)' is annoying to
replicate in languages that don't like playing fast and loose with
types).  :)
---
 python/t/620-stats.py         |  77 +++++++++++++++
 ocaml/tests/Makefile.am       |   1 +
 ocaml/tests/test_620_stats.ml |  77 +++++++++++++++
 golang/Makefile.am            |   3 +-
 golang/libnbd_620_stats.go    | 181 ++++++++++++++++++++++++++++++++++
 5 files changed, 338 insertions(+), 1 deletion(-)
 create mode 100644 python/t/620-stats.py
 create mode 100644 ocaml/tests/test_620_stats.ml
 create mode 100644 golang/libnbd_620_stats.go

diff --git a/python/t/620-stats.py b/python/t/620-stats.py
new file mode 100644
index 00000000..62f8443f
--- /dev/null
+++ b/python/t/620-stats.py
@@ -0,0 +1,77 @@
+# 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
+
+h = nbd.NBD()
+
+# Pre-connection, stats start out at 0
+bs0 = h.stats_bytes_sent()
+cs0 = h.stats_chunks_sent()
+br0 = h.stats_bytes_received()
+cr0 = h.stats_chunks_received()
+
+assert bs0 == 0
+assert cs0 == 0
+assert br0 == 0
+assert cr0 == 0
+
+# Connection performs handshaking, which increments stats.
+# The number of bytes/chunks here may grow over time as more features get
+# automatically negotiated, so merely check that they are non-zero.
+h.connect_command(["nbdkit", "-s", "--exit-with-parent", "null"])
+
+bs1 = h.stats_bytes_sent()
+cs1 = h.stats_chunks_sent()
+br1 = h.stats_bytes_received()
+cr1 = h.stats_chunks_received()
+
+assert cs1 > 0
+assert bs1 > cs1
+assert cr1 > 0
+assert br1 > cr1
+
+# A flush command should be one chunk out, one chunk back (even if
+# structured replies are in use)
+h.flush()
+
+bs2 = h.stats_bytes_sent()
+cs2 = h.stats_chunks_sent()
+br2 = h.stats_bytes_received()
+cr2 = h.stats_chunks_received()
+
+assert bs2 == bs1 + 28
+assert cs2 == cs1 + 1
+assert br2 == br1 + 16   # assumes nbdkit uses simple reply
+assert cr2 == cr1 + 1
+
+# Stats are still readable after the connection closes; we don't know if
+# the server sent reply bytes to our NBD_CMD_DISC, so don't insist on it.
+h.shutdown()
+
+bs3 = h.stats_bytes_sent()
+cs3 = h.stats_chunks_sent()
+br3 = h.stats_bytes_received()
+cr3 = h.stats_chunks_received()
+
+assert bs3 > bs2
+assert cs3 == cs2 + 1
+assert br3 >= br2
+assert cr3 == cr2 + (br3 > br2)
+
+# Try to trigger garbage collection of h
+h = None
diff --git a/ocaml/tests/Makefile.am b/ocaml/tests/Makefile.am
index 22cefb4d..c4751ad3 100644
--- a/ocaml/tests/Makefile.am
+++ b/ocaml/tests/Makefile.am
@@ -42,6 +42,7 @@ ML_TESTS = \
        test_590_aio_copy.ml \
        test_600_debug_callback.ml \
        test_610_exception.ml \
+       test_620_stats.ml \
        $(NULL)

 EXTRA_DIST = $(ML_TESTS)
diff --git a/ocaml/tests/test_620_stats.ml b/ocaml/tests/test_620_stats.ml
new file mode 100644
index 00000000..648096fd
--- /dev/null
+++ b/ocaml/tests/test_620_stats.ml
@@ -0,0 +1,77 @@
+(* 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 () =
+  let nbd = NBD.create () in
+
+  (* Pre-connection, stats start out at 0 *)
+  let bs0 = NBD.stats_bytes_sent nbd in
+  let cs0 = NBD.stats_chunks_sent nbd in
+  let br0 = NBD.stats_bytes_received nbd in
+  let cr0 = NBD.stats_chunks_received nbd in
+  assert (bs0 = 0L);
+  assert (cs0 = 0L);
+  assert (br0 = 0L);
+  assert (cr0 = 0L);
+
+  (* Connection performs handshaking, which increments stats.
+   * The number of bytes/chunks here may grow over time as more features get
+   * automatically negotiated, so merely check that they are non-zero.
+   *)
+  NBD.connect_command nbd ["nbdkit"; "-s"; "--exit-with-parent"; "null"];
+
+  let bs1 = NBD.stats_bytes_sent nbd in
+  let cs1 = NBD.stats_chunks_sent nbd in
+  let br1 = NBD.stats_bytes_received nbd in
+  let cr1 = NBD.stats_chunks_received nbd in
+  assert (cs1 > 0L);
+  assert (bs1 > cs1);
+  assert (cr1 > 0L);
+  assert (br1 > cr1);
+
+  (* A flush command should be one chunk out, one chunk back (even if
+   * structured replies are in use)
+   *)
+  NBD.flush nbd;
+
+  let bs2 = NBD.stats_bytes_sent nbd in
+  let cs2 = NBD.stats_chunks_sent nbd in
+  let br2 = NBD.stats_bytes_received nbd in
+  let cr2 = NBD.stats_chunks_received nbd in
+  assert (bs2 = (Int64.add bs1 28L));
+  assert (cs2 = (Int64.succ cs1));
+  assert (br2 = (Int64.add br1 16L));  (* assumes nbdkit uses simple reply *)
+  assert (cr2 = (Int64.succ cr1));
+
+  (* Stats are still readable after the connection closes; we don't know if
+   * the server sent reply bytes to our NBD_CMD_DISC, so don't insist on it.
+   *)
+  NBD.shutdown nbd;
+
+  let bs3 = NBD.stats_bytes_sent nbd in
+  let cs3 = NBD.stats_chunks_sent nbd in
+  let br3 = NBD.stats_bytes_received nbd in
+  let cr3 = NBD.stats_chunks_received nbd in
+  let fudge = if cr2 = cr3 then 0L else 1L in
+  assert (bs3 > bs2);
+  assert (cs3 = (Int64.succ cs2));
+  assert (br3 >= br2);
+  assert (cr3 = (Int64.add cr2 fudge))
+
+let () = Gc.compact ()
diff --git a/golang/Makefile.am b/golang/Makefile.am
index f170cbc4..765382d4 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
@@ -45,6 +45,7 @@ source_files = \
        libnbd_590_aio_copy_test.go \
        libnbd_600_debug_callback_test.go \
        libnbd_610_error_test.go \
+       libnbd_620_stats.go \
        $(NULL)

 generator_built = \
diff --git a/golang/libnbd_620_stats.go b/golang/libnbd_620_stats.go
new file mode 100644
index 00000000..8d566198
--- /dev/null
+++ b/golang/libnbd_620_stats.go
@@ -0,0 +1,181 @@
+/* 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"
+
+func Test620Stats(t *testing.T) {
+       h, err := Create()
+       if err != nil {
+               t.Fatalf("could not create handle: %s", err)
+       }
+       defer h.Close()
+
+       /* Pre-connection, stats start out at 0 */
+       bs0, err := h.StatsBytesSent()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       cs0, err := h.StatsChunksSent()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       br0, err := h.StatsBytesReceived()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       cr0, err := h.StatsChunksReceived()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+
+       if bs0 != 0 {
+               t.Fatalf("unexpected value for bs0")
+       }
+       if cs0 != 0 {
+               t.Fatalf("unexpected value for cs0")
+       }
+       if br0 != 0 {
+               t.Fatalf("unexpected value for br0")
+       }
+       if cr0 != 0 {
+               t.Fatalf("unexpected value for cr0")
+       }
+
+       /* Connection performs handshaking, which increments stats.
+        * The number of bytes/chunks here may grow over time as more features
+        * get automatically negotiated, so merely check that they are non-zero.
+        */
+       err = h.ConnectCommand([]string{
+               "nbdkit", "-s", "--exit-with-parent", "null",
+       })
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+
+       bs1, err := h.StatsBytesSent()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       cs1, err := h.StatsChunksSent()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       br1, err := h.StatsBytesReceived()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       cr1, err := h.StatsChunksReceived()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+
+       if cs1 == 0 {
+               t.Fatalf("unexpected value for cs1")
+       }
+       if bs1 <= cs1 {
+               t.Fatalf("unexpected value for bs1")
+       }
+       if cr1 == 0 {
+               t.Fatalf("unexpected value for cr1")
+       }
+       if br1 <= cr1 {
+               t.Fatalf("unexpected value for br1")
+       }
+
+       /* A flush command should be one chunk out, one chunk back (even if
+        * structured replies are in use)
+        */
+       err = h.Flush(nil)
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+
+       bs2, err := h.StatsBytesSent()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       cs2, err := h.StatsChunksSent()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       br2, err := h.StatsBytesReceived()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       cr2, err := h.StatsChunksReceived()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+
+       if bs2 != bs1 + 28 {
+               t.Fatalf("unexpected value for bs2")
+       }
+       if cs2 != cs1 + 1 {
+               t.Fatalf("unexpected value for cs2")
+       }
+       if br2 != br1 + 16 {   /* assumes nbdkit uses simple reply */
+               t.Fatalf("unexpected value for br2")
+       }
+       if cr2 != cr1 + 1 {
+               t.Fatalf("unexpected value for cr2")
+       }
+
+       /* Stats are still readable after the connection closes; we don't know 
if
+        * the server sent reply bytes to our NBD_CMD_DISC, so don't insist on 
it.
+        */
+       err = h.Shutdown(nil)
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+
+       bs3, err := h.StatsBytesSent()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       cs3, err := h.StatsChunksSent()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       br3, err := h.StatsBytesReceived()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       cr3, err := h.StatsChunksReceived()
+       if err != nil {
+               t.Fatalf("%s", err)
+       }
+       slop := uint64(1)
+       if br2 == br3 {
+               slop = uint64(0)
+       }
+
+       if bs3 <= bs2 {
+               t.Fatalf("unexpected value for bs3")
+       }
+       if cs3 != cs2 + 1 {
+               t.Fatalf("unexpected value for cs3")
+       }
+       if br3 < br2 {
+               t.Fatalf("unexpected value for br3")
+       }
+       if cr3 != cr2 + slop {
+               t.Fatalf("unexpected value for cr3")
+       }
+}
-- 
2.37.2

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

Reply via email to