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 <xiaw...@linux.vnet.ibm.com>
---
 tests/Makefile                |    2 +
 tests/check-libqblock-qcow2.c |  392 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 394 insertions(+), 0 deletions(-)
 create mode 100644 tests/check-libqblock-qcow2.c

diff --git a/tests/Makefile b/tests/Makefile
index a6a421f..ff9f423 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -136,6 +136,8 @@ $(check-qtest-y): $(qtest-obj-y)
 
 #libqblock build rules
 
+check-libqblock-$(CONFIG_LIBQBLOCK) = tests/check-libqblock-qcow2$(EXESUF)
+
 $(check-libqblock-y): QEMU_INCLUDES += -I$(SRC_PATH)/tests 
-I$(SRC_PATH)/libqblock
 
 $(check-libqblock-y): %$(EXESUF): %.o libqblock.la
diff --git a/tests/check-libqblock-qcow2.c b/tests/check-libqblock-qcow2.c
new file mode 100644
index 0000000..7f92e73
--- /dev/null
+++ b/tests/check-libqblock-qcow2.c
@@ -0,0 +1,392 @@
+/*
+ * QEMU block layer library test
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ *  Wenchao Xia   <xiaw...@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/libqblock_test"
+#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_formattype2str(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_location_info_new(context, &loc_info);
+    g_assert(ret == 0);
+
+    ret = qb_format_info_new(context, &fmt_info);
+    g_assert(ret == 0);
+
+    loc_info->prot_type = QB_PROTO_FILE;
+    fmt_info->fmt_type = QB_FORMAT_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_format_info_delete(context, &fmt_info);
+    qb_location_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_location_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_FORMAT_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_PROTO_NONE);
+        }
+        i--;
+        /* see if there is backing file need to check. */
+        if (backing_loc->prot_type == QB_PROTO_NONE) {
+            g_assert(i < 0);
+            break;
+        }
+        qb_location_info_delete(context, &loc_info);
+        loc_info = qb_location_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_location_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_location_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_location_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;
+}
-- 
1.7.1



Reply via email to