Blame SOURCES/0010-tests-Test-the-Python-plugin-thoroughly.patch

efa7a1
From 7cb79aef2a12f29f1286caf3858001e47214f871 Mon Sep 17 00:00:00 2001
efa7a1
From: "Richard W.M. Jones" <rjones@redhat.com>
efa7a1
Date: Thu, 21 Nov 2019 20:54:41 +0000
60545c
Subject: [PATCH 10/19] tests: Test the Python plugin thoroughly.
efa7a1
efa7a1
This tests the Python plugin thoroughly by issuing client commands
efa7a1
through libnbd and checking we get the expected results.
efa7a1
efa7a1
(cherry picked from commit 8ead4a82ec3227dbecb6cbfc419f1a18f2817d62)
efa7a1
---
efa7a1
 .gitignore                  |   1 +
efa7a1
 README                      |   2 +
efa7a1
 tests/Makefile.am           |  15 +--
efa7a1
 tests/test-lang-plugins.c   |   3 +-
efa7a1
 tests/test-python-plugin.py | 133 +++++++++++++++++++++
efa7a1
 tests/test-python.sh        |  49 ++++++++
efa7a1
 tests/test.py               |  60 ----------
efa7a1
 tests/test_python.py        | 222 ++++++++++++++++++++++++++++++++++++
efa7a1
 8 files changed, 413 insertions(+), 72 deletions(-)
efa7a1
 create mode 100644 tests/test-python-plugin.py
efa7a1
 create mode 100755 tests/test-python.sh
efa7a1
 delete mode 100644 tests/test.py
efa7a1
 create mode 100755 tests/test_python.py
efa7a1
efa7a1
diff --git a/.gitignore b/.gitignore
60545c
index b25ac7fe..e25bd99b 100644
efa7a1
--- a/.gitignore
efa7a1
+++ b/.gitignore
efa7a1
@@ -71,6 +71,7 @@ Makefile.in
efa7a1
 /server/synopsis.c
efa7a1
 /server/test-public
efa7a1
 /stamp-h1
efa7a1
+/tests/__pycache__/
efa7a1
 /tests/disk
efa7a1
 /tests/disk.gz
efa7a1
 /tests/disk.xz
efa7a1
diff --git a/README b/README
60545c
index 40f4cd37..05f1e060 100644
efa7a1
--- a/README
efa7a1
+++ b/README
efa7a1
@@ -130,6 +130,8 @@ For the Python plugin:
efa7a1
 
efa7a1
  - python development libraries
efa7a1
 
efa7a1
+ - python unittest to run the test suite
efa7a1
+
efa7a1
 For the OCaml plugin:
efa7a1
 
efa7a1
  - OCaml >= 4.02.2
efa7a1
diff --git a/tests/Makefile.am b/tests/Makefile.am
60545c
index d225cc63..09103fbb 100644
efa7a1
--- a/tests/Makefile.am
efa7a1
+++ b/tests/Makefile.am
efa7a1
@@ -67,6 +67,7 @@ EXTRA_PROGRAMS =
efa7a1
 TESTS_ENVIRONMENT = \
efa7a1
 	PATH=$(abs_top_builddir):$(PATH) \
efa7a1
 	SRCDIR=$(srcdir) \
efa7a1
+	PYTHON=$(PYTHON) \
efa7a1
 	LIBGUESTFS_ATTACH_METHOD=appliance \
efa7a1
 	LIBGUESTFS_DEBUG=1 \
efa7a1
 	LIBGUESTFS_TRACE=1 \
efa7a1
@@ -160,7 +161,9 @@ EXTRA_DIST = \
efa7a1
 	test-probe-plugin.sh \
efa7a1
 	test-python-exception.sh \
efa7a1
 	test.pl \
efa7a1
-	test.py \
efa7a1
+	test_python.py \
efa7a1
+	test-python-plugin.py \
efa7a1
+	test-python.sh \
efa7a1
 	test-rate.sh \
efa7a1
 	test-rate-dynamic.sh \
efa7a1
 	test.rb \
efa7a1
@@ -801,18 +804,10 @@ endif HAVE_PERL
efa7a1
 if HAVE_PYTHON
efa7a1
 
efa7a1
 TESTS += \
efa7a1
+	test-python.sh \
efa7a1
 	test-python-exception.sh \
efa7a1
 	test-shebang-python.sh \
efa7a1
 	$(NULL)
efa7a1
-LIBGUESTFS_TESTS += test-python
efa7a1
-
efa7a1
-test_python_SOURCES = test-lang-plugins.c test.h
efa7a1
-test_python_CFLAGS = \
efa7a1
-	-DLANG='"python"' -DSCRIPT='"$(srcdir)/test.py"' \
efa7a1
-	$(WARNINGS_CFLAGS) \
efa7a1
-	$(LIBGUESTFS_CFLAGS) \
efa7a1
-	$(NULL)
efa7a1
-test_python_LDADD = libtest.la $(LIBGUESTFS_LIBS)
efa7a1
 
efa7a1
 endif HAVE_PYTHON
efa7a1
 
efa7a1
diff --git a/tests/test-lang-plugins.c b/tests/test-lang-plugins.c
60545c
index ffb19180..93f99381 100644
efa7a1
--- a/tests/test-lang-plugins.c
efa7a1
+++ b/tests/test-lang-plugins.c
efa7a1
@@ -56,8 +56,7 @@ main (int argc, char *argv[])
efa7a1
    */
efa7a1
   s = getenv ("NBDKIT_VALGRIND");
efa7a1
   if (s && strcmp (s, "1") == 0 &&
efa7a1
-      (strcmp (LANG, "python") == 0 ||
efa7a1
-       strcmp (LANG, "ruby") == 0 ||
efa7a1
+      (strcmp (LANG, "ruby") == 0 ||
efa7a1
        strcmp (LANG, "tcl") == 0)) {
efa7a1
     fprintf (stderr, "%s test skipped under valgrind.\n", LANG);
efa7a1
     exit (77);                  /* Tells automake to skip the test. */
efa7a1
diff --git a/tests/test-python-plugin.py b/tests/test-python-plugin.py
efa7a1
new file mode 100644
60545c
index 00000000..8e90bc23
efa7a1
--- /dev/null
efa7a1
+++ b/tests/test-python-plugin.py
efa7a1
@@ -0,0 +1,133 @@
efa7a1
+# nbdkit test plugin
efa7a1
+# Copyright (C) 2019 Red Hat Inc.
efa7a1
+#
efa7a1
+# Redistribution and use in source and binary forms, with or without
efa7a1
+# modification, are permitted provided that the following conditions are
efa7a1
+# met:
efa7a1
+#
efa7a1
+# * Redistributions of source code must retain the above copyright
efa7a1
+# notice, this list of conditions and the following disclaimer.
efa7a1
+#
efa7a1
+# * Redistributions in binary form must reproduce the above copyright
efa7a1
+# notice, this list of conditions and the following disclaimer in the
efa7a1
+# documentation and/or other materials provided with the distribution.
efa7a1
+#
efa7a1
+# * Neither the name of Red Hat nor the names of its contributors may be
efa7a1
+# used to endorse or promote products derived from this software without
efa7a1
+# specific prior written permission.
efa7a1
+#
efa7a1
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
efa7a1
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
efa7a1
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
efa7a1
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
efa7a1
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
efa7a1
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
efa7a1
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
efa7a1
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
efa7a1
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
efa7a1
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
efa7a1
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
efa7a1
+# SUCH DAMAGE.
efa7a1
+
efa7a1
+"""See test-python.py."""
efa7a1
+
efa7a1
+import nbdkit
efa7a1
+import sys
efa7a1
+import pickle
efa7a1
+import base64
efa7a1
+
efa7a1
+API_VERSION = 2
efa7a1
+
efa7a1
+cfg = {}
efa7a1
+
efa7a1
+def config (k, v):
efa7a1
+    global cfg
efa7a1
+    if k == "cfg":
efa7a1
+        cfg = pickle.loads (base64.b64decode (v.encode()))
efa7a1
+
efa7a1
+def config_complete ():
efa7a1
+    print ("set_error = %r" % nbdkit.set_error)
efa7a1
+
efa7a1
+def open (readonly):
efa7a1
+    return {
efa7a1
+        'disk': bytearray (cfg.get ('size', 0))
efa7a1
+    }
efa7a1
+
efa7a1
+def get_size (h):
efa7a1
+    return len (h['disk'])
efa7a1
+
efa7a1
+def is_rotational (h):
efa7a1
+    return cfg.get ('is_rotational', False)
efa7a1
+
efa7a1
+def can_multi_conn (h):
efa7a1
+    return cfg.get ('can_multi_conn', False)
efa7a1
+
efa7a1
+def can_write (h):
efa7a1
+    return cfg.get ('can_write', True)
efa7a1
+
efa7a1
+def can_flush (h):
efa7a1
+    return cfg.get ('can_flush', False)
efa7a1
+
efa7a1
+def can_trim (h):
efa7a1
+    return cfg.get ('can_trim', False)
efa7a1
+
efa7a1
+def can_zero (h):
efa7a1
+    return cfg.get ('can_zero', False)
efa7a1
+
efa7a1
+def can_fast_zero (h):
efa7a1
+    return cfg.get ('can_fast_zero', False)
efa7a1
+
efa7a1
+def can_fua (h):
efa7a1
+    fua = cfg.get ('can_fua', "none")
efa7a1
+    if fua == "none":
efa7a1
+        return nbdkit.FUA_NONE
efa7a1
+    elif fua == "emulate":
efa7a1
+        return nbdkit.FUA_EMULATE
efa7a1
+    elif fua == "native":
efa7a1
+        return nbdkit.FUA_NATIVE
efa7a1
+
efa7a1
+def can_cache (h):
efa7a1
+    cache = cfg.get ('can_cache', "none")
efa7a1
+    if cache == "none":
efa7a1
+        return nbdkit.CACHE_NONE
efa7a1
+    elif cache == "emulate":
efa7a1
+        return nbdkit.CACHE_EMULATE
efa7a1
+    elif cache == "native":
efa7a1
+        return nbdkit.CACHE_NATIVE
efa7a1
+
efa7a1
+def pread (h, buf, offset, flags):
efa7a1
+    assert flags == 0
efa7a1
+    end = offset + len(buf)
efa7a1
+    buf[:] = h['disk'][offset:end]
efa7a1
+
efa7a1
+def pwrite (h, buf, offset, flags):
efa7a1
+    expect_fua = cfg.get ('pwrite_expect_fua', False)
efa7a1
+    actual_fua = bool (flags & nbdkit.FLAG_FUA)
efa7a1
+    assert expect_fua == actual_fua
efa7a1
+    end = offset + len(buf)
efa7a1
+    h['disk'][offset:end] = buf
efa7a1
+
efa7a1
+def flush (h, flags):
efa7a1
+    assert flags == 0
efa7a1
+
efa7a1
+def trim (h, count, offset, flags):
efa7a1
+    expect_fua = cfg.get ('trim_expect_fua', False)
efa7a1
+    actual_fua = bool (flags & nbdkit.FLAG_FUA)
efa7a1
+    assert expect_fua == actual_fua
efa7a1
+    h['disk'][offset:offset+count] = bytearray(count)
efa7a1
+
efa7a1
+def zero (h, count, offset, flags):
efa7a1
+    expect_fua = cfg.get ('zero_expect_fua', False)
efa7a1
+    actual_fua = bool (flags & nbdkit.FLAG_FUA)
efa7a1
+    assert expect_fua == actual_fua
efa7a1
+    expect_may_trim = cfg.get ('zero_expect_may_trim', False)
efa7a1
+    actual_may_trim = bool (flags & nbdkit.FLAG_MAY_TRIM)
efa7a1
+    assert expect_may_trim == actual_may_trim
efa7a1
+    expect_fast_zero = cfg.get ('zero_expect_fast_zero', False)
efa7a1
+    actual_fast_zero = bool (flags & nbdkit.FLAG_FAST_ZERO)
efa7a1
+    assert expect_fast_zero == actual_fast_zero
efa7a1
+    h['disk'][offset:offset+count] = bytearray(count)
efa7a1
+
efa7a1
+def cache (h, count, offset, flags):
efa7a1
+    assert flags == 0
efa7a1
+    # do nothing
efa7a1
diff --git a/tests/test-python.sh b/tests/test-python.sh
efa7a1
new file mode 100755
60545c
index 00000000..50324d0f
efa7a1
--- /dev/null
efa7a1
+++ b/tests/test-python.sh
efa7a1
@@ -0,0 +1,49 @@
efa7a1
+#!/usr/bin/env bash
efa7a1
+# nbdkit
efa7a1
+# Copyright (C) 2019 Red Hat Inc.
efa7a1
+#
efa7a1
+# Redistribution and use in source and binary forms, with or without
efa7a1
+# modification, are permitted provided that the following conditions are
efa7a1
+# met:
efa7a1
+#
efa7a1
+# * Redistributions of source code must retain the above copyright
efa7a1
+# notice, this list of conditions and the following disclaimer.
efa7a1
+#
efa7a1
+# * Redistributions in binary form must reproduce the above copyright
efa7a1
+# notice, this list of conditions and the following disclaimer in the
efa7a1
+# documentation and/or other materials provided with the distribution.
efa7a1
+#
efa7a1
+# * Neither the name of Red Hat nor the names of its contributors may be
efa7a1
+# used to endorse or promote products derived from this software without
efa7a1
+# specific prior written permission.
efa7a1
+#
efa7a1
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
efa7a1
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
efa7a1
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
efa7a1
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
efa7a1
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
efa7a1
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
efa7a1
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
efa7a1
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
efa7a1
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
efa7a1
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
efa7a1
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
efa7a1
+# SUCH DAMAGE.
efa7a1
+
efa7a1
+source ./functions.sh
efa7a1
+set -e
efa7a1
+set -x
efa7a1
+
efa7a1
+requires $PYTHON --version
efa7a1
+requires $PYTHON -c 'import unittest'
efa7a1
+requires $PYTHON -c 'import nbd'
efa7a1
+requires test -f test_python.py
efa7a1
+requires test -f test-python-plugin.py
efa7a1
+
efa7a1
+# Python has proven very difficult to valgrind, therefore it is disabled.
efa7a1
+if [ "$NBDKIT_VALGRIND" = "1" ]; then
efa7a1
+    echo "$0: skipping Python test under valgrind."
efa7a1
+    exit 77
efa7a1
+fi
efa7a1
+
efa7a1
+$PYTHON -m unittest test_python
efa7a1
diff --git a/tests/test.py b/tests/test.py
efa7a1
deleted file mode 100644
60545c
index 4db56623..00000000
efa7a1
--- a/tests/test.py
efa7a1
+++ /dev/null
efa7a1
@@ -1,60 +0,0 @@
efa7a1
-import nbdkit
efa7a1
-
efa7a1
-disk = bytearray(1024*1024)
efa7a1
-
efa7a1
-
efa7a1
-API_VERSION = 2
efa7a1
-
efa7a1
-
efa7a1
-def config_complete():
efa7a1
-    print ("set_error = %r" % nbdkit.set_error)
efa7a1
-
efa7a1
-
efa7a1
-def open(readonly):
efa7a1
-    return 1
efa7a1
-
efa7a1
-
efa7a1
-def get_size(h):
efa7a1
-    global disk
efa7a1
-    return len(disk)
efa7a1
-
efa7a1
-
efa7a1
-def can_write(h):
efa7a1
-    return True
efa7a1
-
efa7a1
-
efa7a1
-def can_flush(h):
efa7a1
-    return True
efa7a1
-
efa7a1
-
efa7a1
-def is_rotational(h):
efa7a1
-    return False
efa7a1
-
efa7a1
-
efa7a1
-def can_trim(h):
efa7a1
-    return True
efa7a1
-
efa7a1
-
efa7a1
-def pread(h, buf, offset, flags):
efa7a1
-    global disk
efa7a1
-    end = offset + len(buf)
efa7a1
-    buf[:] = disk[offset:end]
efa7a1
-
efa7a1
-
efa7a1
-def pwrite(h, buf, offset, flags):
efa7a1
-    global disk
efa7a1
-    end = offset + len(buf)
efa7a1
-    disk[offset:end] = buf
efa7a1
-
efa7a1
-
efa7a1
-def flush(h, flags):
efa7a1
-    pass
efa7a1
-
efa7a1
-
efa7a1
-def trim(h, count, offset, flags):
efa7a1
-    pass
efa7a1
-
efa7a1
-
efa7a1
-def zero(h, count, offset, flags):
efa7a1
-    global disk
efa7a1
-    disk[offset:offset+count] = bytearray(count)
efa7a1
diff --git a/tests/test_python.py b/tests/test_python.py
efa7a1
new file mode 100755
60545c
index 00000000..6b9f2979
efa7a1
--- /dev/null
efa7a1
+++ b/tests/test_python.py
efa7a1
@@ -0,0 +1,222 @@
efa7a1
+#!/usr/bin/env python3
efa7a1
+# nbdkit
efa7a1
+# Copyright (C) 2019 Red Hat Inc.
efa7a1
+#
efa7a1
+# Redistribution and use in source and binary forms, with or without
efa7a1
+# modification, are permitted provided that the following conditions are
efa7a1
+# met:
efa7a1
+#
efa7a1
+# * Redistributions of source code must retain the above copyright
efa7a1
+# notice, this list of conditions and the following disclaimer.
efa7a1
+#
efa7a1
+# * Redistributions in binary form must reproduce the above copyright
efa7a1
+# notice, this list of conditions and the following disclaimer in the
efa7a1
+# documentation and/or other materials provided with the distribution.
efa7a1
+#
efa7a1
+# * Neither the name of Red Hat nor the names of its contributors may be
efa7a1
+# used to endorse or promote products derived from this software without
efa7a1
+# specific prior written permission.
efa7a1
+#
efa7a1
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
efa7a1
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
efa7a1
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
efa7a1
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
efa7a1
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
efa7a1
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
efa7a1
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
efa7a1
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
efa7a1
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
efa7a1
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
efa7a1
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
efa7a1
+# SUCH DAMAGE.
efa7a1
+
efa7a1
+"""
efa7a1
+This tests the Python plugin thoroughly by issuing client commands
efa7a1
+through libnbd and checking we get the expected results.  It uses an
efa7a1
+associated plugin (test-python-plugin.sh).
efa7a1
+"""
efa7a1
+
efa7a1
+import os
efa7a1
+import sys
efa7a1
+import nbd
efa7a1
+import unittest
efa7a1
+import pickle
efa7a1
+import base64
efa7a1
+
efa7a1
+class Test (unittest.TestCase):
efa7a1
+    def setUp (self):
efa7a1
+        self.h = nbd.NBD ()
efa7a1
+
efa7a1
+    def tearDown (self):
efa7a1
+        del self.h
efa7a1
+
efa7a1
+    def connect (self, cfg):
efa7a1
+        cfg = base64.b64encode (pickle.dumps (cfg)).decode()
efa7a1
+        cmd = ["nbdkit", "-v", "-s", "--exit-with-parent",
efa7a1
+               "python", "test-python-plugin.py", "cfg=" + cfg]
efa7a1
+        self.h.connect_command (cmd)
efa7a1
+
efa7a1
+    def test_none (self):
efa7a1
+        """
efa7a1
+        Test we can send an empty pickled test configuration and do
efa7a1
+        nothing else.  This is just to ensure the machinery of the
efa7a1
+        test works.
efa7a1
+        """
efa7a1
+        self.connect ({})
efa7a1
+
efa7a1
+    def test_size_512 (self):
efa7a1
+        """Test the size."""
efa7a1
+        self.connect ({"size": 512})
efa7a1
+        assert self.h.get_size() == 512
efa7a1
+
efa7a1
+    def test_size_1m (self):
efa7a1
+        """Test the size."""
efa7a1
+        self.connect ({"size": 1024*1024})
efa7a1
+        assert self.h.get_size() == 1024*1024
efa7a1
+
efa7a1
+    # Test each flag call.
efa7a1
+    def test_is_rotational_true (self):
efa7a1
+        self.connect ({"size": 512, "is_rotational": True})
efa7a1
+        assert self.h.is_rotational()
efa7a1
+
efa7a1
+    def test_is_rotational_false (self):
efa7a1
+        self.connect ({"size": 512, "is_rotational": False})
efa7a1
+        assert not self.h.is_rotational()
efa7a1
+
efa7a1
+    def test_can_multi_conn_true (self):
efa7a1
+        self.connect ({"size": 512, "can_multi_conn": True})
efa7a1
+        assert self.h.can_multi_conn()
efa7a1
+
efa7a1
+    def test_can_multi_conn_false (self):
efa7a1
+        self.connect ({"size": 512, "can_multi_conn": False})
efa7a1
+        assert not self.h.can_multi_conn()
efa7a1
+
efa7a1
+    def test_read_write (self):
efa7a1
+        self.connect ({"size": 512, "can_write": True})
efa7a1
+        assert not self.h.is_read_only()
efa7a1
+
efa7a1
+    def test_read_only (self):
efa7a1
+        self.connect ({"size": 512, "can_write": False})
efa7a1
+        assert self.h.is_read_only()
efa7a1
+
efa7a1
+    def test_can_flush_true (self):
efa7a1
+        self.connect ({"size": 512, "can_flush": True})
efa7a1
+        assert self.h.can_flush()
efa7a1
+
efa7a1
+    def test_can_flush_false (self):
efa7a1
+        self.connect ({"size": 512, "can_flush": False})
efa7a1
+        assert not self.h.can_flush()
efa7a1
+
efa7a1
+    def test_can_trim_true (self):
efa7a1
+        self.connect ({"size": 512, "can_trim": True})
efa7a1
+        assert self.h.can_trim()
efa7a1
+
efa7a1
+    def test_can_trim_false (self):
efa7a1
+        self.connect ({"size": 512, "can_trim": False})
efa7a1
+        assert not self.h.can_trim()
efa7a1
+
efa7a1
+    # nbdkit can always zero because it emulates it.
efa7a1
+    #self.connect ({"size": 512, "can_zero": True})
efa7a1
+    #assert self.h.can_zero()
efa7a1
+    #self.connect ({"size": 512, "can_zero": False})
efa7a1
+    #assert not self.h.can_zero()
efa7a1
+
efa7a1
+    def test_can_fast_zero_true (self):
efa7a1
+        self.connect ({"size": 512, "can_fast_zero": True})
efa7a1
+        assert self.h.can_fast_zero()
efa7a1
+
efa7a1
+    def test_can_fast_zero_false (self):
efa7a1
+        self.connect ({"size": 512, "can_fast_zero": False})
efa7a1
+        assert not self.h.can_fast_zero()
efa7a1
+
efa7a1
+    def test_can_fua_none (self):
efa7a1
+        self.connect ({"size": 512, "can_fua": "none"})
efa7a1
+        assert not self.h.can_fua()
efa7a1
+
efa7a1
+    def test_can_fua_emulate (self):
efa7a1
+        self.connect ({"size": 512, "can_fua": "emulate"})
efa7a1
+        assert self.h.can_fua()
efa7a1
+
efa7a1
+    def test_can_fua_native (self):
efa7a1
+        self.connect ({"size": 512, "can_fua": "native"})
efa7a1
+        assert self.h.can_fua()
efa7a1
+
efa7a1
+    def test_can_cache_none (self):
efa7a1
+        self.connect ({"size": 512, "can_cache": "none"})
efa7a1
+        assert not self.h.can_cache()
efa7a1
+
efa7a1
+    def test_can_cache_emulate (self):
efa7a1
+        self.connect ({"size": 512, "can_cache": "emulate"})
efa7a1
+        assert self.h.can_cache()
efa7a1
+
efa7a1
+    def test_can_cache_native (self):
efa7a1
+        self.connect ({"size": 512, "can_cache": "native"})
efa7a1
+        assert self.h.can_cache()
efa7a1
+
efa7a1
+    # Not yet implemented: can_extents.
efa7a1
+
efa7a1
+    def test_pread (self):
efa7a1
+        """Test pread."""
efa7a1
+        self.connect ({"size": 512})
efa7a1
+        buf = self.h.pread (512, 0)
efa7a1
+        assert buf == bytearray (512)
efa7a1
+
efa7a1
+    # Test pwrite + flags.
efa7a1
+    def test_pwrite (self):
efa7a1
+        self.connect ({"size": 512})
efa7a1
+        buf = bytearray (512)
efa7a1
+        self.h.pwrite (buf, 0)
efa7a1
+
efa7a1
+    def test_pwrite_fua (self):
efa7a1
+        self.connect ({"size": 512,
efa7a1
+                       "can_fua": "native",
efa7a1
+                       "pwrite_expect_fua": True})
efa7a1
+        buf = bytearray (512)
efa7a1
+        self.h.pwrite (buf, 0, nbd.CMD_FLAG_FUA)
efa7a1
+
efa7a1
+    def test_flush (self):
efa7a1
+        """Test flush."""
efa7a1
+        self.connect ({"size": 512, "can_flush": True})
efa7a1
+        self.h.flush ()
efa7a1
+
efa7a1
+    # Test trim + flags.
efa7a1
+    def test_trim (self):
efa7a1
+        self.connect ({"size": 512, "can_trim": True})
efa7a1
+        self.h.trim (512, 0)
efa7a1
+
efa7a1
+    def test_trim_fua (self):
efa7a1
+        self.connect ({"size": 512,
efa7a1
+                       "can_trim": True,
efa7a1
+                       "can_fua": "native",
efa7a1
+                       "trim_expect_fua": True})
efa7a1
+        self.h.trim (512, 0, nbd.CMD_FLAG_FUA)
efa7a1
+
efa7a1
+    # Test zero + flags.
efa7a1
+    def test_zero (self):
efa7a1
+        self.connect ({"size": 512, "can_zero": True})
efa7a1
+        self.h.zero (512, 0, nbd.CMD_FLAG_NO_HOLE)
efa7a1
+
efa7a1
+    def test_zero_fua (self):
efa7a1
+        self.connect ({"size": 512,
efa7a1
+                       "can_zero": True,
efa7a1
+                       "can_fua": "native",
efa7a1
+                       "zero_expect_fua": True})
efa7a1
+        self.h.zero (512, 0, nbd.CMD_FLAG_NO_HOLE | nbd.CMD_FLAG_FUA)
efa7a1
+
efa7a1
+    def test_zero_may_trim (self):
efa7a1
+        self.connect ({"size": 512,
efa7a1
+                       "can_zero": True,
efa7a1
+                       "zero_expect_may_trim": True})
efa7a1
+        self.h.zero (512, 0, 0) # absence of nbd.CMD_FLAG_NO_HOLE
efa7a1
+
efa7a1
+    def test_zero_fast_zero (self):
efa7a1
+        self.connect ({"size": 512,
efa7a1
+                       "can_zero": True,
efa7a1
+                       "can_fast_zero": True,
efa7a1
+                       "zero_expect_fast_zero": True})
efa7a1
+        self.h.zero (512, 0, nbd.CMD_FLAG_NO_HOLE | nbd.CMD_FLAG_FAST_ZERO)
efa7a1
+
efa7a1
+    def test_cache (self):
efa7a1
+        """Test cache."""
efa7a1
+        self.connect ({"size": 512, "can_cache": "native"})
efa7a1
+        self.h.cache (512, 0)
efa7a1
-- 
efa7a1
2.18.2
efa7a1