All of lore.kernel.org
 help / color / mirror / Atom feed
From: Fabiano Rosas <farosas@suse.de>
To: qemu-devel@nongnu.org
Cc: "Peter Xu" <peterx@redhat.com>,
	"Junjie Cao" <junjie.cao@intel.com>,
	"Daniel P. Berrangé" <berrange@redhat.com>
Subject: [PULL 39/43] tests/unit: add pread/pwrite _all tests for io channel file
Date: Thu, 23 Apr 2026 16:19:53 -0300	[thread overview]
Message-ID: <20260423191958.1440-40-farosas@suse.de> (raw)
In-Reply-To: <20260423191958.1440-1-farosas@suse.de>

From: Junjie Cao <junjie.cao@intel.com>

Add unit tests for the new qio_channel_pread{v,}_all{,_eof}() and
qio_channel_pwrite{v,}_all() APIs.

The basic tests write data to a file channel, then read it back at
various offsets using both the single-buffer and iovec variants to
make sure the round-trip produces identical content.  The _eof tests
verify all three return cases -- full read (1), clean EOF (0), and
partial-then-EOF (-1 with error set) -- and check that the strict
wrappers (preadv_all / pread_all) treat a clean EOF as an error.

All tests are guarded by CONFIG_PREADV since the underlying channel
methods require preadv(2).

Signed-off-by: Junjie Cao <junjie.cao@intel.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Acked-by: Daniel P. Berrangé <berrange@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260413214549.926435-5-junjie.cao@intel.com
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 tests/unit/test-io-channel-file.c | 207 ++++++++++++++++++++++++++++++
 1 file changed, 207 insertions(+)

diff --git a/tests/unit/test-io-channel-file.c b/tests/unit/test-io-channel-file.c
index 1977006ce9..b597350dca 100644
--- a/tests/unit/test-io-channel-file.c
+++ b/tests/unit/test-io-channel-file.c
@@ -102,6 +102,203 @@ static void test_io_channel_fd(void)
 }
 
 
+#ifdef CONFIG_PREADV
+static void test_io_channel_pread_all(void)
+{
+    QIOChannel *ioc;
+    char write_buf[] = "Hello World, pread_all";
+    char read_buf[sizeof(write_buf)] = {0};
+    int ret;
+
+    unlink(TEST_FILE);
+    ioc = QIO_CHANNEL(qio_channel_file_new_path(
+                          TEST_FILE,
+                          O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
+                          TEST_MASK,
+                          &error_abort));
+
+    ret = qio_channel_pwrite_all(ioc, write_buf, sizeof(write_buf),
+                                 0, &error_abort);
+    g_assert_cmpint(ret, ==, 0);
+
+    /* Read back at offset 0 */
+    ret = qio_channel_pread_all(ioc, read_buf, sizeof(read_buf),
+                                0, &error_abort);
+    g_assert_cmpint(ret, ==, 0);
+    g_assert_cmpmem(write_buf, sizeof(write_buf),
+                    read_buf, sizeof(read_buf));
+
+    /* Read at a non-zero offset */
+    memset(read_buf, 0, sizeof(read_buf));
+    ret = qio_channel_pread_all(ioc, read_buf, sizeof(write_buf) - 7,
+                                7, &error_abort);
+    g_assert_cmpint(ret, ==, 0);
+    g_assert_cmpmem(write_buf + 7, sizeof(write_buf) - 7,
+                    read_buf, sizeof(write_buf) - 7);
+
+    unlink(TEST_FILE);
+    object_unref(OBJECT(ioc));
+}
+
+static void test_io_channel_preadv_all(void)
+{
+    QIOChannel *ioc;
+    char write_buf[256];
+    char read_buf[256] = {0};
+    struct iovec write_iov[2];
+    struct iovec read_iov[2];
+    int ret;
+    size_t i;
+
+    for (i = 0; i < sizeof(write_buf); i++) {
+        write_buf[i] = i & 0xff;
+    }
+
+    unlink(TEST_FILE);
+    ioc = QIO_CHANNEL(qio_channel_file_new_path(
+                          TEST_FILE,
+                          O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
+                          TEST_MASK,
+                          &error_abort));
+
+    /* Write using pwritev_all with 2 iovecs */
+    write_iov[0].iov_base = write_buf;
+    write_iov[0].iov_len = 128;
+    write_iov[1].iov_base = write_buf + 128;
+    write_iov[1].iov_len = 128;
+    ret = qio_channel_pwritev_all(ioc, write_iov, 2, 0, &error_abort);
+    g_assert_cmpint(ret, ==, 0);
+
+    /* Read back using preadv_all with 2 iovecs */
+    read_iov[0].iov_base = read_buf;
+    read_iov[0].iov_len = 128;
+    read_iov[1].iov_base = read_buf + 128;
+    read_iov[1].iov_len = 128;
+    ret = qio_channel_preadv_all(ioc, read_iov, 2, 0, &error_abort);
+    g_assert_cmpint(ret, ==, 0);
+
+    g_assert_cmpmem(write_buf, sizeof(write_buf),
+                    read_buf, sizeof(read_buf));
+
+    /* Read at non-zero offset with preadv_all */
+    memset(read_buf, 0, sizeof(read_buf));
+    read_iov[0].iov_base = read_buf;
+    read_iov[0].iov_len = 64;
+    read_iov[1].iov_base = read_buf + 64;
+    read_iov[1].iov_len = 64;
+    ret = qio_channel_preadv_all(ioc, read_iov, 2, 128, &error_abort);
+    g_assert_cmpint(ret, ==, 0);
+
+    g_assert_cmpmem(write_buf + 128, 128,
+                    read_buf, 128);
+
+    unlink(TEST_FILE);
+    object_unref(OBJECT(ioc));
+}
+
+static void test_io_channel_preadv_all_eof(void)
+{
+    QIOChannel *ioc;
+    char write_buf[] = "Hello World, preadv_all_eof";
+    char read_buf[sizeof(write_buf)] = {0};
+    struct iovec iov;
+    int ret;
+    Error *err = NULL;
+
+    unlink(TEST_FILE);
+    ioc = QIO_CHANNEL(qio_channel_file_new_path(
+                          TEST_FILE,
+                          O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
+                          TEST_MASK,
+                          &error_abort));
+
+    ret = qio_channel_pwrite_all(ioc, write_buf, sizeof(write_buf),
+                                 0, &error_abort);
+    g_assert_cmpint(ret, ==, 0);
+
+    /* Full read succeeds: should return 1 */
+    iov.iov_base = read_buf;
+    iov.iov_len = sizeof(read_buf);
+    ret = qio_channel_preadv_all_eof(ioc, &iov, 1, 0, &error_abort);
+    g_assert_cmpint(ret, ==, 1);
+    g_assert_cmpmem(write_buf, sizeof(write_buf),
+                    read_buf, sizeof(read_buf));
+
+    /* Clean EOF: offset at file end, should return 0 */
+    iov.iov_base = read_buf;
+    iov.iov_len = 1;
+    ret = qio_channel_preadv_all_eof(ioc, &iov, 1,
+                                     sizeof(write_buf), &err);
+    g_assert_cmpint(ret, ==, 0);
+    g_assert_null(err);
+
+    /* Partial EOF: start before end, request extends past */
+    iov.iov_base = read_buf;
+    iov.iov_len = 8;
+    ret = qio_channel_preadv_all_eof(ioc, &iov, 1,
+                                     sizeof(write_buf) - 4, &err);
+    g_assert_cmpint(ret, ==, -1);
+    g_assert_nonnull(err);
+    error_free(err);
+    err = NULL;
+
+    /* Strict wrapper (preadv_all) treats clean EOF as error */
+    iov.iov_base = read_buf;
+    iov.iov_len = 1;
+    ret = qio_channel_preadv_all(ioc, &iov, 1,
+                                 sizeof(write_buf), &err);
+    g_assert_cmpint(ret, ==, -1);
+    g_assert_nonnull(err);
+    error_free(err);
+
+    unlink(TEST_FILE);
+    object_unref(OBJECT(ioc));
+}
+
+static void test_io_channel_pread_all_eof(void)
+{
+    QIOChannel *ioc;
+    char write_buf[] = "Hello World, pread_all_eof";
+    char read_buf[sizeof(write_buf)] = {0};
+    int ret;
+    Error *err = NULL;
+
+    unlink(TEST_FILE);
+    ioc = QIO_CHANNEL(qio_channel_file_new_path(
+                          TEST_FILE,
+                          O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
+                          TEST_MASK,
+                          &error_abort));
+
+    ret = qio_channel_pwrite_all(ioc, write_buf, sizeof(write_buf),
+                                 0, &error_abort);
+    g_assert_cmpint(ret, ==, 0);
+
+    /* Full read succeeds: should return 1 */
+    ret = qio_channel_pread_all_eof(ioc, read_buf, sizeof(read_buf),
+                                    0, &error_abort);
+    g_assert_cmpint(ret, ==, 1);
+    g_assert_cmpmem(write_buf, sizeof(write_buf),
+                    read_buf, sizeof(read_buf));
+
+    /* Clean EOF: should return 0 */
+    ret = qio_channel_pread_all_eof(ioc, read_buf, 1,
+                                    sizeof(write_buf), &err);
+    g_assert_cmpint(ret, ==, 0);
+    g_assert_null(err);
+
+    /* Partial EOF: should return -1 */
+    ret = qio_channel_pread_all_eof(ioc, read_buf, 8,
+                                    sizeof(write_buf) - 4, &err);
+    g_assert_cmpint(ret, ==, -1);
+    g_assert_nonnull(err);
+    error_free(err);
+
+    unlink(TEST_FILE);
+    object_unref(OBJECT(ioc));
+}
+#endif /* CONFIG_PREADV */
+
 #ifndef _WIN32
 static void test_io_channel_pipe(bool async)
 {
@@ -147,6 +344,16 @@ int main(int argc, char **argv)
     g_test_add_func("/io/channel/file", test_io_channel_file);
     g_test_add_func("/io/channel/file/rdwr", test_io_channel_file_rdwr);
     g_test_add_func("/io/channel/file/fd", test_io_channel_fd);
+#ifdef CONFIG_PREADV
+    g_test_add_func("/io/channel/file/pread-all",
+                    test_io_channel_pread_all);
+    g_test_add_func("/io/channel/file/preadv-all",
+                    test_io_channel_preadv_all);
+    g_test_add_func("/io/channel/file/preadv-all-eof",
+                    test_io_channel_preadv_all_eof);
+    g_test_add_func("/io/channel/file/pread-all-eof",
+                    test_io_channel_pread_all_eof);
+#endif
 #ifndef _WIN32
     g_test_add_func("/io/channel/pipe/sync", test_io_channel_pipe_sync);
     g_test_add_func("/io/channel/pipe/async", test_io_channel_pipe_async);
-- 
2.51.0



  parent reply	other threads:[~2026-04-23 19:24 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-23 19:19 [PULL 00/43] Migration patches for 2026-04-23 Fabiano Rosas
2026-04-23 19:19 ` [PULL 01/43] checkpatch: Allow spaces after all coroutine annotations Fabiano Rosas
2026-04-23 19:19 ` [PULL 02/43] tests/functional: Make socat wait longer in migration exec test Fabiano Rosas
2026-04-23 19:19 ` [PULL 03/43] migration: vmstate_save_state_v: fix double error_setg Fabiano Rosas
2026-04-23 19:19 ` [PULL 04/43] migration: make vmstate_save_state_v() static Fabiano Rosas
2026-04-23 19:19 ` [PULL 05/43] migration: make .post_save() a void function Fabiano Rosas
2026-04-23 19:19 ` [PULL 06/43] migration: vmstate_load_state(): add some newlines Fabiano Rosas
2026-04-23 19:19 ` [PULL 07/43] migration: vmstate_save/load_state(): refactor tracing errors Fabiano Rosas
2026-04-23 19:19 ` [PULL 08/43] migration: factor out vmstate_pre_save() from vmstate_save_state() Fabiano Rosas
2026-04-23 19:19 ` [PULL 09/43] migration: factor out vmstate_save_field() " Fabiano Rosas
2026-04-23 19:19 ` [PULL 10/43] migration: factor out vmstate_pre_load() from vmstate_load_state() Fabiano Rosas
2026-04-23 19:19 ` [PULL 11/43] migration: factor out vmstate_load_field() " Fabiano Rosas
2026-04-23 19:19 ` [PULL 12/43] migration: factor out vmstate_post_load() " Fabiano Rosas
2026-04-23 19:19 ` [PULL 13/43] migration: convert vmstate_subsection_save/load functions to bool Fabiano Rosas
2026-04-23 19:19 ` [PULL 14/43] migration: VMStateInfo: introduce new handlers with errp Fabiano Rosas
2026-04-23 19:19 ` [PULL 15/43] migration: introduce vmstate_load_vmsd() and vmstate_save_vmsd() Fabiano Rosas
2026-04-23 19:19 ` [PULL 16/43] migration/cpr: move to new migration APIs Fabiano Rosas
2026-04-23 19:19 ` [PULL 17/43] migration/savevm: " Fabiano Rosas
2026-04-23 19:19 ` [PULL 18/43] hw/s390x/css: drop use of .err_hint for vmstate Fabiano Rosas
2026-04-23 19:19 ` [PULL 19/43] migration: drop VMStateField.err_hint Fabiano Rosas
2026-04-23 19:19 ` [PULL 20/43] migration/vmstate-types: move to new migration APIs Fabiano Rosas
2026-04-23 19:19 ` [PULL 21/43] migration: Tweak description of migration property multifd-compression Fabiano Rosas
2026-04-23 19:19 ` [PULL 22/43] tests/qtest/migration: Add mapped-ram/postcopy validation test Fabiano Rosas
2026-04-23 19:19 ` [PULL 23/43] migration: fix QIOChannelFile leak on error in file_connect_outgoing Fabiano Rosas
2026-04-23 19:19 ` [PULL 24/43] vmstate: Pass in struct itself for VMSTATE_ARRAY_OF_POINTER Fabiano Rosas
2026-04-23 19:19 ` [PULL 25/43] vmstate: Pass in struct itself for VMSTATE_VARRAY_OF_POINTER_UINT32 Fabiano Rosas
2026-04-23 19:19 ` [PULL 26/43] vmstate: Do not set size for VMS_ARRAY_OF_POINTER Fabiano Rosas
2026-04-23 19:19 ` [PULL 27/43] vmstate: Update max_elems early and check field compressable once Fabiano Rosas
2026-04-23 19:19 ` [PULL 28/43] vmstate: Rename VMS_NULLPTR_MARKER to VMS_MARKER_PTR_NULL Fabiano Rosas
2026-04-23 19:19 ` [PULL 29/43] vmstate: Introduce vmstate_save_field_with_vmdesc() Fabiano Rosas
2026-04-23 19:19 ` [PULL 30/43] vmstate: Allow vmstate_info_nullptr to emit non-NULL markers Fabiano Rosas
2026-04-23 19:19 ` [PULL 31/43] vmstate: Implement load of ptr marker in vmstate core Fabiano Rosas
2026-04-23 19:19 ` [PULL 32/43] vmstate: Implement VMS_ARRAY_OF_POINTER_AUTO_ALLOC Fabiano Rosas
2026-04-23 19:19 ` [PULL 33/43] vmstate: Stop checking size for nullptr compression Fabiano Rosas
2026-04-23 19:19 ` [PULL 34/43] tests/unit/test-vmstate: add tests for VMS_ARRAY_OF_POINTER_AUTO_ALLOC Fabiano Rosas
2026-04-23 19:19 ` [PULL 35/43] migration: validate page_size in mapped-ram header before use Fabiano Rosas
2026-04-23 19:19 ` [PULL 36/43] io/channel: introduce qio_channel_pread{v, }_all{, _eof}() Fabiano Rosas
2026-04-23 19:19 ` [PULL 37/43] io/channel: introduce qio_channel_pwrite{v,}_all() Fabiano Rosas
2026-04-23 19:19 ` [PULL 38/43] migration/file: fix type mismatch and NULL deref in multifd_file_recv_data Fabiano Rosas
2026-04-23 19:19 ` Fabiano Rosas [this message]
2026-04-23 19:19 ` [PULL 40/43] tests/qtest/migration: fix fd leak in ufd_version_check Fabiano Rosas
2026-04-23 19:19 ` [PULL 41/43] migration/qemu-file: switch buffer_at functions to positioned I/O _all helpers Fabiano Rosas
2026-04-23 19:19 ` [PULL 42/43] migration/file: switch file_write_ramblock_iov to pwritev_all Fabiano Rosas
2026-04-23 19:19 ` [PULL 43/43] migration/qemu-file: drop incorrect const from qemu_get_buffer_at buf Fabiano Rosas
2026-04-25 16:58 ` [PULL 00/43] Migration patches for 2026-04-23 Stefan Hajnoczi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260423191958.1440-40-farosas@suse.de \
    --to=farosas@suse.de \
    --cc=berrange@redhat.com \
    --cc=junjie.cao@intel.com \
    --cc=peterx@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.