Patchwork [V16,9/9] libqblock: test: libqblock test example

login
register
mail settings
Submitter Wayne Xia
Date Jan. 29, 2013, 4:51 a.m.
Message ID <1359435076-13673-10-git-send-email-xiawenc@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/216433/
State New
Headers show

Comments

Wayne Xia - Jan. 29, 2013, 4:51 a.m.
In this example, first it will create some qcow2 images, then try get
information including backing file relationship, then it will do sync IO on
the image.

Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
---
 tests/check-libqblock-qcow2.c |  392 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 392 insertions(+), 0 deletions(-)
 create mode 100644 tests/check-libqblock-qcow2.c
Paolo Bonzini - Jan. 29, 2013, 12:46 p.m.
Il 29/01/2013 05:51, Wenchao Xia ha scritto:
>   In this example, first it will create some qcow2 images, then try get
> information including backing file relationship, then it will do sync IO on
> the image.
> 
> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>

Patch 8 alone won't compile.  This line:

+check-libqblock-$(CONFIG_LIBQBLOCK) = tests/check-libqblock-qcow2$(EXESUF)

has to be moved to this patch.

Please do this instead:

# in patch 9
check-libqblock-y = tests/check-libqblock-qcow2$(EXESUF)
...
# in patch 8
check-unit-$(CONFIG_LIBQBLOCK) += $(check-libqblock-y)

Paolo

> ---
>  tests/check-libqblock-qcow2.c |  392 +++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 392 insertions(+), 0 deletions(-)
>  create mode 100644 tests/check-libqblock-qcow2.c
> 
> diff --git a/tests/check-libqblock-qcow2.c b/tests/check-libqblock-qcow2.c
> new file mode 100644
> index 0000000..0cbe8da
> --- /dev/null
> +++ b/tests/check-libqblock-qcow2.c
> @@ -0,0 +1,392 @@
> +/*
> + * QEMU block layer library test
> + *
> + * Copyright IBM, Corp. 2013
> + *
> + * Authors:
> + *  Wenchao Xia   <xiawenc@linux.vnet.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + * Limitation:
> + *    1 filename do not support relative path, to save trouble in creating
> + * backing files.
> + */
> +
> +#include <glib.h>
> +#include <stdarg.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <inttypes.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +
> +
> +#include "libqblock.h"
> +#include "libqtest.h"
> +
> +#define LIBQB_TEST_ENV_DIR "LIBQBLOCK_TEST_DIR"
> +#define LIBQB_TEST_DEFAULT_DIR "/tmp"
> +#define LIBQB_TEST_DEFAULT_FILENAME "libqblock_qcow2_test_img"
> +
> +typedef struct LibqbTestSettings {
> +    const char *image_filename;
> +    uint64_t image_size;
> +    unsigned int num_backings;
> +    unsigned int io_buf_size;
> +    uint64_t io_offset;
> +    int print_flag;
> +} LibqbTestSettings;
> +
> +LibqbTestSettings libqb_test_settings;
> +
> +static void print_loc(const QBlockLocationInfo *loc)
> +{
> +    if (loc == NULL) {
> +        printf("loc is NULL.");
> +        return;
> +    }
> +    switch (loc->prot_type) {
> +    case QB_PROTO_NONE:
> +        printf("protocol type [none].");
> +        break;
> +    case QB_PROTO_FILE:
> +        printf("protocol type [file], filename [%s].",
> +               loc->o_file.filename);
> +        break;
> +    default:
> +        printf("protocol type not supported.");
> +        break;
> +    }
> +}
> +
> +static void print_info_image_static(QBlockStaticInfo *info)
> +{
> +    const uint64_t *virt_size = qb_get_virt_size(info);
> +    const QBlockLocationInfo *backing_loc = qb_get_backing_loc(info);
> +    g_assert(virt_size != NULL);
> +
> +    printf("=======image location:\n");
> +    print_loc(&info->loc);
> +    printf("\nvirtual_size %" PRId64 ", format type %d [%s]",
> +           *(virt_size),
> +           info->fmt.fmt_type, qb_fmttype2str(info->fmt.fmt_type));
> +    printf("\nbacking image location:\n");
> +    print_loc(backing_loc);
> +    printf("\n");
> +}
> +
> +static char *generate_backing_filename(const char *filename, int index)
> +{
> +    char *backing_filename = NULL;
> +
> +    backing_filename = g_strdup_printf("%s_backing_%d", filename, index);
> +    return backing_filename;
> +}
> +
> +/* get filename in a full path */
> +static const char *get_filename(const char *path)
> +{
> +    const char *filename;
> +    filename = strrchr(path, '/');
> +    if (filename == NULL) {
> +        filename = path;
> +    } else {
> +        filename++;
> +    }
> +    return filename;
> +}
> +
> +/* create a chain of files, num_backings must >= 0. */
> +static void files_create_qcow2(const char *filename,
> +                               int num_backings,
> +                               uint64_t virt_size)
> +{
> +    QBlockContext *context = NULL;
> +    QBlockImage *qbi = NULL;
> +    QBlockLocationInfo *loc_info = NULL;
> +    QBlockFormatInfo *fmt_info = NULL;
> +    int ret;
> +    int index;
> +    int flag;
> +    char *backing_filename = NULL, *new_filename = NULL;
> +    const char *relative_filename = NULL;
> +
> +    ret = qb_context_new(&context);
> +    g_assert(ret == 0);
> +
> +    ret = qb_image_new(context, &qbi);
> +    g_assert(ret == 0);
> +
> +    ret = qb_loc_info_new(context, &loc_info);
> +    g_assert(ret == 0);
> +
> +    ret = qb_fmt_info_new(context, &fmt_info);
> +    g_assert(ret == 0);
> +
> +    loc_info->prot_type = QB_PROTO_FILE;
> +    fmt_info->fmt_type = QB_FMT_QCOW2;
> +    fmt_info->virt_size = virt_size;
> +    flag = 0;
> +
> +    index = 0;
> +    while (index < num_backings) {
> +        new_filename = generate_backing_filename(filename, index);
> +        loc_info->o_file.filename = new_filename;
> +        if (backing_filename != NULL) {
> +            fmt_info->o_qcow2.backing_loc.prot_type = QB_PROTO_FILE;
> +            relative_filename = get_filename(backing_filename);
> +            fmt_info->o_qcow2.backing_loc.o_file.filename =
> +                                                             relative_filename;
> +        }
> +        ret = qb_create(context, qbi, loc_info, fmt_info, flag);
> +        g_assert(ret == 0);
> +        free(backing_filename);
> +        backing_filename = new_filename;
> +        new_filename = NULL;
> +        index++;
> +    }
> +
> +    loc_info->o_file.filename = filename;
> +    if (backing_filename != NULL) {
> +        fmt_info->o_qcow2.backing_loc.prot_type = QB_PROTO_FILE;
> +        relative_filename = get_filename(backing_filename);
> +        fmt_info->o_qcow2.backing_loc.o_file.filename =
> +                                                         relative_filename;
> +    }
> +    ret = qb_create(context, qbi, loc_info, fmt_info, flag);
> +    g_assert(ret == 0);
> +    free(backing_filename);
> +
> +    qb_fmt_info_delete(context, &fmt_info);
> +    qb_loc_info_delete(context, &loc_info);
> +    qb_image_unref(context, &qbi);
> +    qb_context_delete(&context);
> +    return;
> +}
> +
> +static void files_delete(const char *filename,
> +                         int num_backings,
> +                         uint64_t virt_size)
> +{
> +    char *new_filename = NULL;
> +    int index = 0;
> +    while (index < num_backings) {
> +        new_filename = generate_backing_filename(filename, index);
> +        unlink(new_filename);
> +        free(new_filename);
> +        index++;
> +    }
> +    unlink(filename);
> +}
> +
> +static void testcase_info_image_static(void)
> +{
> +    const char *filename = libqb_test_settings.image_filename;
> +    uint64_t image_size = libqb_test_settings.image_size;
> +    int num_backings = libqb_test_settings.num_backings;
> +    QBlockContext *context = NULL;
> +    QBlockImage *qbi = NULL;
> +    QBlockLocationInfo *loc_info = NULL;
> +    int ret, flag;
> +    QBlockStaticInfo *info_st = NULL;
> +    int i;
> +    char *backing_filename = NULL;
> +    const uint64_t *virt_size = NULL;
> +    const QBlockLocationInfo *backing_loc = NULL;
> +
> +    ret = qb_context_new(&context);
> +    g_assert(ret == 0);
> +
> +    ret = qb_image_new(context, &qbi);
> +    g_assert(ret == 0);
> +
> +    ret = qb_loc_info_new(context, &loc_info);
> +    g_assert(ret == 0);
> +
> +    loc_info->prot_type = QB_PROTO_FILE;
> +    loc_info->o_file.filename = filename;
> +    flag = LIBQBLOCK_O_NO_BACKING;
> +    ret = qb_open(context, qbi, loc_info, NULL, flag);
> +    g_assert(ret == 0);
> +
> +    i = num_backings - 1;
> +    while (1) {
> +        ret = qb_info_image_static_get(context, qbi, &info_st);
> +        g_assert(ret == 0);
> +        if (libqb_test_settings.print_flag > 0) {
> +            print_info_image_static(info_st);
> +        }
> +        qb_close(context, qbi);
> +
> +        /* checking the information */
> +        g_assert(info_st->loc.prot_type == loc_info->prot_type);
> +        ret = strcmp(info_st->loc.o_file.filename,
> +                     loc_info->o_file.filename);
> +
> +        g_assert(ret == 0);
> +        g_assert(info_st->fmt.fmt_type == QB_FMT_QCOW2);
> +        virt_size = qb_get_virt_size(info_st);
> +        g_assert(virt_size != NULL);
> +        g_assert(*virt_size == image_size);
> +        backing_loc = qb_get_backing_loc(info_st);
> +        /* qcow2 have always backing file property */
> +        g_assert(backing_loc != NULL);
> +        if (i >= 0) {
> +            /* it should have backing file */
> +            g_assert(backing_loc->prot_type == QB_PROTO_FILE);
> +            backing_filename = generate_backing_filename(filename, i);
> +            ret = strcmp(backing_filename, backing_loc->o_file.filename);
> +            g_assert(ret == 0);
> +            g_free(backing_filename);
> +        } else {
> +            g_assert(backing_loc->prot_type == QB_FMT_NONE);
> +        }
> +        i--;
> +        /* see if there is backing file need to check. */
> +        if (backing_loc->prot_type == QB_FMT_NONE) {
> +            g_assert(i < 0);
> +            break;
> +        }
> +        qb_loc_info_delete(context, &loc_info);
> +        loc_info = qb_loc_info_dup(backing_loc);
> +        ret = qb_open(context, qbi, loc_info, NULL, flag);
> +        g_assert(ret == 0);
> +        qb_info_image_static_delete(context, &info_st);
> +    }
> +    qb_info_image_static_delete(context, &info_st);
> +
> +    qb_loc_info_delete(context, &loc_info);
> +    qb_image_unref(context, &qbi);
> +    qb_context_delete(&context);
> +    return;
> +}
> +
> +/* assuming the image is new created */
> +static void testcase_sync_io(void)
> +{
> +    const char *filename = libqb_test_settings.image_filename;
> +    uint64_t io_buf_size = libqb_test_settings.io_buf_size;
> +    uint64_t io_offset = libqb_test_settings.io_offset;;
> +    unsigned char *buf_r, *buf_w;
> +    uint64_t i;
> +    unsigned int rand_value;
> +
> +    buf_r = g_malloc0(io_buf_size);
> +    buf_w = g_malloc0(io_buf_size);
> +    for (i = 0; i < io_buf_size; i++) {
> +        rand_value = g_test_rand_int_range(0, 255);
> +        buf_w[i] = (unsigned char)rand_value;
> +    }
> +
> +    QBlockContext *context = NULL;
> +    QBlockImage *qbi = NULL;
> +    QBlockLocationInfo *loc_info = NULL;
> +    int ret, flag;
> +
> +    ret = qb_context_new(&context);
> +    g_assert(ret == 0);
> +
> +    ret = qb_image_new(context, &qbi);
> +    g_assert(ret == 0);
> +
> +    ret = qb_loc_info_new(context, &loc_info);
> +    g_assert(ret == 0);
> +
> +
> +    loc_info->prot_type = QB_PROTO_FILE;
> +    loc_info->o_file.filename = filename;
> +    flag = LIBQBLOCK_O_RDWR;
> +    ret = qb_open(context, qbi, loc_info, NULL, flag);
> +    g_assert(ret == 0);
> +
> +    int status;
> +    int64_t len;
> +    ret = qb_check_allocation(context, qbi, io_offset, io_buf_size,
> +                                       &status, &len);
> +    g_assert(ret == 0);
> +    g_assert(status == 0);
> +    g_assert(len == io_buf_size);
> +
> +    ret = qb_write(context, qbi, buf_w, io_buf_size, io_offset);
> +    g_assert(ret == io_buf_size);
> +
> +    ret = qb_read(context, qbi, buf_r, io_buf_size, io_offset);
> +    g_assert(ret == io_buf_size);
> +
> +    int cmp = memcmp(buf_r, buf_w, io_buf_size);
> +    g_assert(cmp == 0);
> +
> +    ret = qb_check_allocation(context, qbi, io_offset, io_buf_size,
> +                                       &status, &len);
> +    g_assert(ret == 0);
> +    g_assert(status == 1);
> +    g_assert(len == io_buf_size);
> +
> +    qb_close(context, qbi);
> +
> +    qb_loc_info_delete(context, &loc_info);
> +    qb_image_unref(context, &qbi);
> +    qb_context_delete(&context);
> +    g_free(buf_r);
> +    g_free(buf_w);
> +    return;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    const char *root_dir;
> +    const char *name = LIBQB_TEST_DEFAULT_FILENAME;
> +    int ret;
> +    int dir_created = 0;
> +    char *filename;
> +
> +    root_dir = getenv(LIBQB_TEST_ENV_DIR);
> +    if (root_dir == NULL) {
> +        root_dir = LIBQB_TEST_DEFAULT_DIR;
> +    }
> +
> +    ret = access(root_dir, F_OK);
> +    if (ret != 0) {
> +        /* try mkdir */
> +        ret = mkdir(root_dir, 0755);
> +        g_assert(ret == 0);
> +        dir_created = 1;
> +    }
> +
> +    filename = g_strdup_printf("%s/%s", root_dir, name);
> +
> +    g_test_init(&argc, &argv, NULL);
> +    g_test_rand_int();
> +
> +    libqb_test_settings.image_filename = filename;
> +    libqb_test_settings.image_size =
> +                            1024 * 1024 * g_test_rand_int_range(1, 1024);
> +    libqb_test_settings.num_backings = g_test_rand_int_range(0, 10);
> +    libqb_test_settings.io_buf_size = g_test_rand_int_range(1, 1024 * 1024);
> +    libqb_test_settings.io_offset = g_test_rand_int_range(0,
> +            libqb_test_settings.image_size - libqb_test_settings.io_buf_size);
> +
> +    files_create_qcow2(libqb_test_settings.image_filename,
> +                       libqb_test_settings.num_backings,
> +                       libqb_test_settings.image_size);
> +
> +    g_test_add_func("/libqblock/sync_info_image_static",
> +                      testcase_info_image_static);
> +    g_test_add_func("/libqblock/sync_io", testcase_sync_io);
> +
> +    ret = g_test_run();
> +    files_delete(libqb_test_settings.image_filename,
> +                 libqb_test_settings.num_backings,
> +                 libqb_test_settings.image_size);
> +
> +    g_free(filename);
> +    if (dir_created) {
> +        ret = rmdir(root_dir);
> +        g_assert(ret == 0);
> +    }
> +    return ret;
> +}
>

Patch

diff --git a/tests/check-libqblock-qcow2.c b/tests/check-libqblock-qcow2.c
new file mode 100644
index 0000000..0cbe8da
--- /dev/null
+++ b/tests/check-libqblock-qcow2.c
@@ -0,0 +1,392 @@ 
+/*
+ * QEMU block layer library test
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ *  Wenchao Xia   <xiawenc@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ * Limitation:
+ *    1 filename do not support relative path, to save trouble in creating
+ * backing files.
+ */
+
+#include <glib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+#include "libqblock.h"
+#include "libqtest.h"
+
+#define LIBQB_TEST_ENV_DIR "LIBQBLOCK_TEST_DIR"
+#define LIBQB_TEST_DEFAULT_DIR "/tmp"
+#define LIBQB_TEST_DEFAULT_FILENAME "libqblock_qcow2_test_img"
+
+typedef struct LibqbTestSettings {
+    const char *image_filename;
+    uint64_t image_size;
+    unsigned int num_backings;
+    unsigned int io_buf_size;
+    uint64_t io_offset;
+    int print_flag;
+} LibqbTestSettings;
+
+LibqbTestSettings libqb_test_settings;
+
+static void print_loc(const QBlockLocationInfo *loc)
+{
+    if (loc == NULL) {
+        printf("loc is NULL.");
+        return;
+    }
+    switch (loc->prot_type) {
+    case QB_PROTO_NONE:
+        printf("protocol type [none].");
+        break;
+    case QB_PROTO_FILE:
+        printf("protocol type [file], filename [%s].",
+               loc->o_file.filename);
+        break;
+    default:
+        printf("protocol type not supported.");
+        break;
+    }
+}
+
+static void print_info_image_static(QBlockStaticInfo *info)
+{
+    const uint64_t *virt_size = qb_get_virt_size(info);
+    const QBlockLocationInfo *backing_loc = qb_get_backing_loc(info);
+    g_assert(virt_size != NULL);
+
+    printf("=======image location:\n");
+    print_loc(&info->loc);
+    printf("\nvirtual_size %" PRId64 ", format type %d [%s]",
+           *(virt_size),
+           info->fmt.fmt_type, qb_fmttype2str(info->fmt.fmt_type));
+    printf("\nbacking image location:\n");
+    print_loc(backing_loc);
+    printf("\n");
+}
+
+static char *generate_backing_filename(const char *filename, int index)
+{
+    char *backing_filename = NULL;
+
+    backing_filename = g_strdup_printf("%s_backing_%d", filename, index);
+    return backing_filename;
+}
+
+/* get filename in a full path */
+static const char *get_filename(const char *path)
+{
+    const char *filename;
+    filename = strrchr(path, '/');
+    if (filename == NULL) {
+        filename = path;
+    } else {
+        filename++;
+    }
+    return filename;
+}
+
+/* create a chain of files, num_backings must >= 0. */
+static void files_create_qcow2(const char *filename,
+                               int num_backings,
+                               uint64_t virt_size)
+{
+    QBlockContext *context = NULL;
+    QBlockImage *qbi = NULL;
+    QBlockLocationInfo *loc_info = NULL;
+    QBlockFormatInfo *fmt_info = NULL;
+    int ret;
+    int index;
+    int flag;
+    char *backing_filename = NULL, *new_filename = NULL;
+    const char *relative_filename = NULL;
+
+    ret = qb_context_new(&context);
+    g_assert(ret == 0);
+
+    ret = qb_image_new(context, &qbi);
+    g_assert(ret == 0);
+
+    ret = qb_loc_info_new(context, &loc_info);
+    g_assert(ret == 0);
+
+    ret = qb_fmt_info_new(context, &fmt_info);
+    g_assert(ret == 0);
+
+    loc_info->prot_type = QB_PROTO_FILE;
+    fmt_info->fmt_type = QB_FMT_QCOW2;
+    fmt_info->virt_size = virt_size;
+    flag = 0;
+
+    index = 0;
+    while (index < num_backings) {
+        new_filename = generate_backing_filename(filename, index);
+        loc_info->o_file.filename = new_filename;
+        if (backing_filename != NULL) {
+            fmt_info->o_qcow2.backing_loc.prot_type = QB_PROTO_FILE;
+            relative_filename = get_filename(backing_filename);
+            fmt_info->o_qcow2.backing_loc.o_file.filename =
+                                                             relative_filename;
+        }
+        ret = qb_create(context, qbi, loc_info, fmt_info, flag);
+        g_assert(ret == 0);
+        free(backing_filename);
+        backing_filename = new_filename;
+        new_filename = NULL;
+        index++;
+    }
+
+    loc_info->o_file.filename = filename;
+    if (backing_filename != NULL) {
+        fmt_info->o_qcow2.backing_loc.prot_type = QB_PROTO_FILE;
+        relative_filename = get_filename(backing_filename);
+        fmt_info->o_qcow2.backing_loc.o_file.filename =
+                                                         relative_filename;
+    }
+    ret = qb_create(context, qbi, loc_info, fmt_info, flag);
+    g_assert(ret == 0);
+    free(backing_filename);
+
+    qb_fmt_info_delete(context, &fmt_info);
+    qb_loc_info_delete(context, &loc_info);
+    qb_image_unref(context, &qbi);
+    qb_context_delete(&context);
+    return;
+}
+
+static void files_delete(const char *filename,
+                         int num_backings,
+                         uint64_t virt_size)
+{
+    char *new_filename = NULL;
+    int index = 0;
+    while (index < num_backings) {
+        new_filename = generate_backing_filename(filename, index);
+        unlink(new_filename);
+        free(new_filename);
+        index++;
+    }
+    unlink(filename);
+}
+
+static void testcase_info_image_static(void)
+{
+    const char *filename = libqb_test_settings.image_filename;
+    uint64_t image_size = libqb_test_settings.image_size;
+    int num_backings = libqb_test_settings.num_backings;
+    QBlockContext *context = NULL;
+    QBlockImage *qbi = NULL;
+    QBlockLocationInfo *loc_info = NULL;
+    int ret, flag;
+    QBlockStaticInfo *info_st = NULL;
+    int i;
+    char *backing_filename = NULL;
+    const uint64_t *virt_size = NULL;
+    const QBlockLocationInfo *backing_loc = NULL;
+
+    ret = qb_context_new(&context);
+    g_assert(ret == 0);
+
+    ret = qb_image_new(context, &qbi);
+    g_assert(ret == 0);
+
+    ret = qb_loc_info_new(context, &loc_info);
+    g_assert(ret == 0);
+
+    loc_info->prot_type = QB_PROTO_FILE;
+    loc_info->o_file.filename = filename;
+    flag = LIBQBLOCK_O_NO_BACKING;
+    ret = qb_open(context, qbi, loc_info, NULL, flag);
+    g_assert(ret == 0);
+
+    i = num_backings - 1;
+    while (1) {
+        ret = qb_info_image_static_get(context, qbi, &info_st);
+        g_assert(ret == 0);
+        if (libqb_test_settings.print_flag > 0) {
+            print_info_image_static(info_st);
+        }
+        qb_close(context, qbi);
+
+        /* checking the information */
+        g_assert(info_st->loc.prot_type == loc_info->prot_type);
+        ret = strcmp(info_st->loc.o_file.filename,
+                     loc_info->o_file.filename);
+
+        g_assert(ret == 0);
+        g_assert(info_st->fmt.fmt_type == QB_FMT_QCOW2);
+        virt_size = qb_get_virt_size(info_st);
+        g_assert(virt_size != NULL);
+        g_assert(*virt_size == image_size);
+        backing_loc = qb_get_backing_loc(info_st);
+        /* qcow2 have always backing file property */
+        g_assert(backing_loc != NULL);
+        if (i >= 0) {
+            /* it should have backing file */
+            g_assert(backing_loc->prot_type == QB_PROTO_FILE);
+            backing_filename = generate_backing_filename(filename, i);
+            ret = strcmp(backing_filename, backing_loc->o_file.filename);
+            g_assert(ret == 0);
+            g_free(backing_filename);
+        } else {
+            g_assert(backing_loc->prot_type == QB_FMT_NONE);
+        }
+        i--;
+        /* see if there is backing file need to check. */
+        if (backing_loc->prot_type == QB_FMT_NONE) {
+            g_assert(i < 0);
+            break;
+        }
+        qb_loc_info_delete(context, &loc_info);
+        loc_info = qb_loc_info_dup(backing_loc);
+        ret = qb_open(context, qbi, loc_info, NULL, flag);
+        g_assert(ret == 0);
+        qb_info_image_static_delete(context, &info_st);
+    }
+    qb_info_image_static_delete(context, &info_st);
+
+    qb_loc_info_delete(context, &loc_info);
+    qb_image_unref(context, &qbi);
+    qb_context_delete(&context);
+    return;
+}
+
+/* assuming the image is new created */
+static void testcase_sync_io(void)
+{
+    const char *filename = libqb_test_settings.image_filename;
+    uint64_t io_buf_size = libqb_test_settings.io_buf_size;
+    uint64_t io_offset = libqb_test_settings.io_offset;;
+    unsigned char *buf_r, *buf_w;
+    uint64_t i;
+    unsigned int rand_value;
+
+    buf_r = g_malloc0(io_buf_size);
+    buf_w = g_malloc0(io_buf_size);
+    for (i = 0; i < io_buf_size; i++) {
+        rand_value = g_test_rand_int_range(0, 255);
+        buf_w[i] = (unsigned char)rand_value;
+    }
+
+    QBlockContext *context = NULL;
+    QBlockImage *qbi = NULL;
+    QBlockLocationInfo *loc_info = NULL;
+    int ret, flag;
+
+    ret = qb_context_new(&context);
+    g_assert(ret == 0);
+
+    ret = qb_image_new(context, &qbi);
+    g_assert(ret == 0);
+
+    ret = qb_loc_info_new(context, &loc_info);
+    g_assert(ret == 0);
+
+
+    loc_info->prot_type = QB_PROTO_FILE;
+    loc_info->o_file.filename = filename;
+    flag = LIBQBLOCK_O_RDWR;
+    ret = qb_open(context, qbi, loc_info, NULL, flag);
+    g_assert(ret == 0);
+
+    int status;
+    int64_t len;
+    ret = qb_check_allocation(context, qbi, io_offset, io_buf_size,
+                                       &status, &len);
+    g_assert(ret == 0);
+    g_assert(status == 0);
+    g_assert(len == io_buf_size);
+
+    ret = qb_write(context, qbi, buf_w, io_buf_size, io_offset);
+    g_assert(ret == io_buf_size);
+
+    ret = qb_read(context, qbi, buf_r, io_buf_size, io_offset);
+    g_assert(ret == io_buf_size);
+
+    int cmp = memcmp(buf_r, buf_w, io_buf_size);
+    g_assert(cmp == 0);
+
+    ret = qb_check_allocation(context, qbi, io_offset, io_buf_size,
+                                       &status, &len);
+    g_assert(ret == 0);
+    g_assert(status == 1);
+    g_assert(len == io_buf_size);
+
+    qb_close(context, qbi);
+
+    qb_loc_info_delete(context, &loc_info);
+    qb_image_unref(context, &qbi);
+    qb_context_delete(&context);
+    g_free(buf_r);
+    g_free(buf_w);
+    return;
+}
+
+int main(int argc, char **argv)
+{
+    const char *root_dir;
+    const char *name = LIBQB_TEST_DEFAULT_FILENAME;
+    int ret;
+    int dir_created = 0;
+    char *filename;
+
+    root_dir = getenv(LIBQB_TEST_ENV_DIR);
+    if (root_dir == NULL) {
+        root_dir = LIBQB_TEST_DEFAULT_DIR;
+    }
+
+    ret = access(root_dir, F_OK);
+    if (ret != 0) {
+        /* try mkdir */
+        ret = mkdir(root_dir, 0755);
+        g_assert(ret == 0);
+        dir_created = 1;
+    }
+
+    filename = g_strdup_printf("%s/%s", root_dir, name);
+
+    g_test_init(&argc, &argv, NULL);
+    g_test_rand_int();
+
+    libqb_test_settings.image_filename = filename;
+    libqb_test_settings.image_size =
+                            1024 * 1024 * g_test_rand_int_range(1, 1024);
+    libqb_test_settings.num_backings = g_test_rand_int_range(0, 10);
+    libqb_test_settings.io_buf_size = g_test_rand_int_range(1, 1024 * 1024);
+    libqb_test_settings.io_offset = g_test_rand_int_range(0,
+            libqb_test_settings.image_size - libqb_test_settings.io_buf_size);
+
+    files_create_qcow2(libqb_test_settings.image_filename,
+                       libqb_test_settings.num_backings,
+                       libqb_test_settings.image_size);
+
+    g_test_add_func("/libqblock/sync_info_image_static",
+                      testcase_info_image_static);
+    g_test_add_func("/libqblock/sync_io", testcase_sync_io);
+
+    ret = g_test_run();
+    files_delete(libqb_test_settings.image_filename,
+                 libqb_test_settings.num_backings,
+                 libqb_test_settings.image_size);
+
+    g_free(filename);
+    if (dir_created) {
+        ret = rmdir(root_dir);
+        g_assert(ret == 0);
+    }
+    return ret;
+}