[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 05/10] qapi: test cases for QEMUFile input/output vi
From: |
Michael Roth |
Subject: |
[Qemu-devel] [PATCH 05/10] qapi: test cases for QEMUFile input/output visitors |
Date: |
Fri, 14 Oct 2011 13:19:57 -0500 |
Signed-off-by: Michael Roth <address@hidden>
---
Makefile | 2 +-
test-visitor.c | 404 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 405 insertions(+), 1 deletions(-)
diff --git a/Makefile b/Makefile
index f63fc02..50803b0 100644
--- a/Makefile
+++ b/Makefile
@@ -204,7 +204,7 @@ qmp-marshal.c: $(SRC_PATH)/qapi-schema.json
$(SRC_PATH)/scripts/qapi-commands.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -m
-o "." < $<, " GEN $@")
test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h
test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o
$(qapi-obj-y) error.o osdep.o $(oslib-obj-y) qjson.o json-streamer.o
json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o
$(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o
$(qapi-obj-y) error.o osdep.o $(oslib-obj-y) qjson.o json-streamer.o
json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o
$(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
qapi/qemu-file-input-visitor.o qapi/qemu-file-output-visitor.o qemu-file.o
test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c
test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c
test-qmp-commands.h) $(qapi-obj-y)
test-qmp-commands: test-qmp-commands.o qfloat.o qint.o qdict.o qstring.o
qlist.o qbool.o $(qapi-obj-y) error.o osdep.o $(oslib-obj-y) qjson.o
json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o
$(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
$(qapi-dir)/test-qmp-marshal.o module.o
diff --git a/test-visitor.c b/test-visitor.c
index 847ce14..15a9ce9 100644
--- a/test-visitor.c
+++ b/test-visitor.c
@@ -4,6 +4,10 @@
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
#include "qemu-objects.h"
+#include "qapi/qemu-file-output-visitor.h"
+#include "qapi/qemu-file-input-visitor.h"
+#include "hw/hw.h"
+#include "qemu-common.h"
typedef struct TestStruct
{
@@ -323,6 +327,404 @@ static void test_nested_enums(void)
qapi_free_NestedEnumsOne(nested_enums_cpy);
}
+#define TEST_QEMU_FILE_PATH "/tmp/test_qemu_file_visitors"
+
+typedef struct QEMUFileValue {
+ union {
+ bool boolean;
+ double number;
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+ uint64_t u64;
+ int8_t s8;
+ int16_t s16;
+ int32_t s32;
+ int64_t s64;
+ uintmax_t umax;
+ } value;
+ union {
+ uint8_t u8[32];
+ uint16_t u16[32];
+ uint32_t u32[32];
+ uint64_t u64[32];
+ int8_t s8[32];
+ int16_t s16[32];
+ int32_t s32[32];
+ int64_t s64[32];
+ uintmax_t umax[32];
+ } array;
+ size_t array_len;
+ enum {
+ QFV_BOOL = 0,
+ QFV_NUMBER,
+ QFV_U8,
+ QFV_U16,
+ QFV_U32,
+ QFV_U64,
+ QFV_S8,
+ QFV_S16,
+ QFV_S32,
+ QFV_S64,
+ QFV_U8_ARRAY,
+ QFV_EOL,
+ } type;
+} QEMUFileValue;
+
+QEMUFileValue qfvalues[] = {
+ { .value.boolean = true, .type = QFV_BOOL },
+ { .value.boolean = false, .type = QFV_BOOL },
+ { .value.number = 3.14159265, .type = QFV_NUMBER },
+ { .value.u8 = 0, .type = QFV_U8 },
+ { .value.u8 = 1, .type = QFV_U8 },
+ { .value.u8 = 128, .type = QFV_U8 },
+ { .value.u8 = 255u, .type = QFV_U8 },
+ { .value.u16 = 0, .type = QFV_U16 },
+ { .value.u16 = 1, .type = QFV_U16 },
+ { .value.u16 = 32768, .type = QFV_U16 },
+ { .value.u16 = 65535u, .type = QFV_U16 },
+ { .value.u32 = 0, .type = QFV_U32 },
+ { .value.u32 = 1, .type = QFV_U32 },
+ { .value.u32 = 2147483648, .type = QFV_U32 },
+ { .value.u32 = 4294967295u, .type = QFV_U32 },
+ { .value.u64 = 0, .type = QFV_U64 },
+ { .value.u64 = 1, .type = QFV_U64 },
+ { .value.u64 = 9223372036854775808u, .type = QFV_U64 },
+ { .value.u64 = 18446744073709551615u, .type = QFV_U64 },
+ { .value.s8 = 0, .type = QFV_S8 },
+ { .value.s8 = 1, .type = QFV_S8 },
+ { .value.s8 = 128, .type = QFV_S8 },
+ { .value.s8 = -1, .type = QFV_S8 },
+ { .value.s16 = 0, .type = QFV_S16 },
+ { .value.s16 = 1, .type = QFV_S16 },
+ { .value.s16 = 32768, .type = QFV_S16 },
+ { .value.s16 = -1, .type = QFV_S16 },
+ { .value.s32 = 0, .type = QFV_S32 },
+ { .value.s32 = 1, .type = QFV_S32 },
+ { .value.s32 = 2147483648, .type = QFV_S32 },
+ { .value.s32 = -1, .type = QFV_S32 },
+ { .value.s64 = 0, .type = QFV_S64 },
+ { .value.s64 = 1, .type = QFV_S64 },
+ { .value.s64 = 9223372036854775808u, .type = QFV_S64 },
+ { .value.s64 = -1, .type = QFV_S64 },
+ { .array.u8 = { }, .array_len = 0, .type = QFV_U8_ARRAY },
+ { .array.u8 = { 1, 2, 3, 4 }, .array_len = 4, .type = QFV_U8_ARRAY },
+ { .type = QFV_EOL }
+};
+
+static void qfv_process(QEMUFileValue *qfv, bool visitor, bool write,
+ void *opaque)
+{
+ int i;
+ void *ptr;
+
+ switch (qfv->type) {
+ case QFV_BOOL:
+ if (visitor) {
+ visit_type_bool(opaque, &qfv->value.boolean, NULL, NULL);
+ } else {
+ if (write) {
+ qemu_put_byte(opaque, qfv->value.boolean);
+ } else {
+ qfv->value.boolean = qemu_get_byte(opaque);
+ }
+ }
+ break;
+ case QFV_NUMBER:
+ if (visitor) {
+ visit_type_number(opaque, &qfv->value.number, NULL, NULL);
+ } else {
+ if (write) {
+ qemu_put_be64s(opaque, (uint64_t *)&qfv->value.number);
+ } else {
+ qemu_get_be64s(opaque, (uint64_t *)&qfv->value.number);
+ }
+ }
+ break;
+ case QFV_U8:
+ if (visitor) {
+ visit_type_uint8(opaque, &qfv->value.u8, NULL, NULL);
+ } else {
+ if (write) {
+ qemu_put_byte(opaque, qfv->value.u8);
+ } else {
+ qfv->value.u8 = qemu_get_byte(opaque);
+ }
+ }
+ break;
+ case QFV_U16:
+ if (visitor) {
+ visit_type_uint16(opaque, &qfv->value.u16, NULL, NULL);
+ } else {
+ if (write) {
+ qemu_put_be16(opaque, qfv->value.u16);
+ } else {
+ qfv->value.u16 = qemu_get_be16(opaque);
+ }
+ }
+ break;
+ case QFV_U32:
+ if (visitor) {
+ visit_type_uint32(opaque, &qfv->value.u32, NULL, NULL);
+ } else {
+ if (write) {
+ qemu_put_be32(opaque, qfv->value.u32);
+ } else {
+ qfv->value.u32 = qemu_get_be32(opaque);
+ }
+ }
+ break;
+ case QFV_U64:
+ if (visitor) {
+ visit_type_uint64(opaque, &qfv->value.u64, NULL, NULL);
+ } else {
+ if (write) {
+ qemu_put_be64(opaque, qfv->value.u64);
+ } else {
+ qfv->value.u64 = qemu_get_be64(opaque);
+ }
+ }
+ break;
+ case QFV_S8:
+ if (visitor) {
+ visit_type_int8(opaque, &qfv->value.s8, NULL, NULL);
+ } else {
+ if (write) {
+ qemu_put_byte(opaque, qfv->value.s8);
+ } else {
+ qfv->value.s8 = qemu_get_byte(opaque);
+ }
+ }
+ break;
+ case QFV_S16:
+ if (visitor) {
+ visit_type_int16(opaque, &qfv->value.s16, NULL, NULL);
+ } else {
+ if (write) {
+ qemu_put_be16(opaque, qfv->value.s16);
+ } else {
+ qfv->value.s16 = qemu_get_be16(opaque);
+ }
+ }
+ break;
+ case QFV_S32:
+ if (visitor) {
+ visit_type_int32(opaque, &qfv->value.s32, NULL, NULL);
+ } else {
+ if (write) {
+ qemu_put_be32(opaque, qfv->value.s32);
+ } else {
+ qfv->value.s32 = qemu_get_be32(opaque);
+ }
+ }
+ break;
+ case QFV_S64:
+ if (visitor) {
+ visit_type_int64(opaque, &qfv->value.s64, NULL, NULL);
+ } else {
+ if (write) {
+ qemu_put_be64(opaque, qfv->value.s64);
+ } else {
+ qfv->value.s64 = qemu_get_be64(opaque);
+ }
+ }
+ break;
+ case QFV_U8_ARRAY:
+ if (visitor) {
+ ptr = qfv->array.u8;
+ visit_start_array(opaque, (void **)&ptr, NULL,
+ qfv->array_len, sizeof(uint8_t), NULL);
+ for (i = 0; i < qfv->array_len; i++, visit_next_array(opaque,
NULL)) {
+ visit_type_uint8(opaque, &((uint8_t *)ptr)[i], NULL, NULL);
+ }
+ visit_end_array(opaque, NULL);
+ } else {
+ for (i = 0; i < qfv->array_len; i++) {
+ if (write) {
+ qemu_put_byte(opaque, qfv->array.u8[i]);
+ } else {
+ qfv->array.u8[i] = qemu_get_byte(opaque);
+ }
+ }
+ }
+ break;
+ default:
+ return;
+ }
+}
+
+static void qfv_visitor_write(QEMUFileValue *qfv, Visitor *v)
+{
+ qfv_process(qfv, true, true, v);
+}
+
+static void qfv_visitor_read(QEMUFileValue *qfv, Visitor *v)
+{
+ qfv_process(qfv, true, false, v);
+}
+
+static void qfv_write(QEMUFileValue *qfv, QEMUFile *f)
+{
+ qfv_process(qfv, false, true, f);
+}
+
+static void qfv_read(QEMUFileValue *qfv, QEMUFile *f)
+{
+ qfv_process(qfv, false, false, f);
+}
+
+static void test_qemu_file_in_visitor(void)
+{
+ QEMUFile *f1, *f2;
+ QemuFileInputVisitor *qfi;
+ QemuFileOutputVisitor *qfo;
+ Visitor *v;
+ QEMUFileValue qfval1, qfval2;
+ int i, j;
+ TestStruct ts, *pts;
+ TestStructList *lts;
+
+ /* write our test scalars/arrays */
+ f1 = qemu_fopen(TEST_QEMU_FILE_PATH, "wb");
+ g_assert(f1);
+ qfo = qemu_file_output_visitor_new(f1);
+ v = qemu_file_output_get_visitor(qfo);
+ for (i = 0; qfvalues[i].type != QFV_EOL; i++) {
+ qfv_write(&qfvalues[i], f1);
+ }
+ /* write our test struct/list. qemu_put_* interfaces have
+ * no analogue for this and instead rely on byte arrays,
+ * so we'll write this using a visitor and simply test
+ * visitor input/output compatibility
+ */
+ /* write a simple struct */
+ ts.x = 42;
+ ts.y = 43;
+ pts = &ts;
+ visit_type_TestStruct(v, &pts, NULL, NULL);
+ /* throw in a linked list as well */
+ lts = g_malloc0(sizeof(*lts));
+ lts->value = g_malloc0(sizeof(TestStruct));
+ lts->value->x = 44;
+ lts->value->y = 45;
+ lts->next = g_malloc0(sizeof(*lts));
+ lts->next->value = g_malloc0(sizeof(TestStruct));
+ lts->next->value->x = 46;
+ lts->next->value->y = 47;
+ visit_type_TestStructList(v, <s, NULL, NULL);
+ g_free(lts->next->value);
+ g_free(lts->next);
+ g_free(lts->value);
+ g_free(lts);
+
+ qemu_file_output_visitor_cleanup(qfo);
+ qemu_fclose(f1);
+
+ /* make sure qemu_get_be* and input visitor read same/correct input */
+ f1 = qemu_fopen(TEST_QEMU_FILE_PATH, "rb");
+ f2 = qemu_fopen(TEST_QEMU_FILE_PATH, "rb");
+ qfi = qemu_file_input_visitor_new(f2);
+ g_assert(qfi);
+ v = qemu_file_input_get_visitor(qfi);
+ g_assert(v);
+ for (i = 0; qfvalues[i].type != QFV_EOL; i++) {
+ qfval1.value.umax = qfval2.value.umax = 0;
+ memset(qfval1.array.umax, 0, sizeof(qfval1.array.umax));
+ memset(qfval2.array.umax, 0, sizeof(qfval2.array.umax));
+ qfval1.type = qfval2.type = qfvalues[i].type;
+ qfval1.array_len = qfval2.array_len = qfvalues[i].array_len;
+ qfv_read(&qfval1, f1);
+ qfv_visitor_read(&qfval2, v);
+ if (qfvalues[i].type >= QFV_U8_ARRAY) {
+ for (j = 0; j < qfvalues[i].array_len; j++) {
+ g_assert(qfval1.array.u8[j] == qfval2.array.u8[j]);
+ g_assert(qfval2.array.u8[j] == qfvalues[i].array.u8[j]);
+ }
+ } else {
+ g_assert(qfval1.value.umax == qfval2.value.umax);
+ g_assert(qfval2.value.umax == qfvalues[i].value.umax);
+ }
+ }
+ qemu_file_input_visitor_cleanup(qfi);
+ qemu_fclose(f1);
+ qemu_fclose(f2);
+ unlink(TEST_QEMU_FILE_PATH);
+}
+
+static void test_qemu_file_out_visitor(void)
+{
+ QEMUFile *f;
+ QemuFileOutputVisitor *qfo;
+ Visitor *v;
+ QEMUFileValue qfval1;
+ int i, j;
+ TestStruct ts, *pts;
+ TestStructList *lts;
+
+ /* write test scalars/arrays using an output visitor */
+ f = qemu_fopen(TEST_QEMU_FILE_PATH, "wb");
+ g_assert(f);
+ qfo = qemu_file_output_visitor_new(f);
+ g_assert(qfo);
+ v = qemu_file_output_get_visitor(qfo);
+ g_assert(v);
+ for (i = 0; qfvalues[i].type != QFV_EOL; i++) {
+ qfv_visitor_write(&qfvalues[i], v);
+ }
+ /* write a simple struct */
+ ts.x = 42;
+ ts.y = 43;
+ pts = &ts;
+ visit_type_TestStruct(v, &pts, NULL, NULL);
+ /* throw in a linked list as well */
+ lts = g_malloc0(sizeof(*lts));
+ lts->value = g_malloc0(sizeof(TestStruct));
+ lts->value->x = 44;
+ lts->value->y = 45;
+ lts->next = g_malloc0(sizeof(*lts));
+ lts->next->value = g_malloc0(sizeof(TestStruct));
+ lts->next->value->x = 46;
+ lts->next->value->y = 47;
+ visit_type_TestStructList(v, <s, NULL, NULL);
+ g_free(lts->next->value);
+ g_free(lts->next);
+ g_free(lts->value);
+ g_free(lts);
+
+ qemu_file_output_visitor_cleanup(qfo);
+ qemu_fclose(f);
+
+ /* make sure output visitor wrote the expected values */
+ f = qemu_fopen(TEST_QEMU_FILE_PATH, "rb");
+ g_assert(f);
+ for (i = 0; qfvalues[i].type != QFV_EOL; i++) {
+ qfval1.type = qfvalues[i].type;
+ qfval1.value.umax = 0;
+ memset(qfval1.array.umax, 0, sizeof(qfval1.array.umax));
+ qfval1.array_len = qfvalues[i].array_len;
+
+ qfv_read(&qfval1, f);
+ if (qfvalues[i].type >= QFV_U8_ARRAY) {
+ for (j = 0; j < qfvalues[i].array_len; j++) {
+ g_assert(qfval1.array.u8[j] == qfvalues[i].array.u8[j]);
+ }
+ } else {
+ g_assert(qfval1.value.umax == qfvalues[i].value.umax);
+ }
+ }
+ /* test the struct */
+ g_assert(qemu_get_be64(f) == ts.x);
+ g_assert(qemu_get_be64(f) == ts.y);
+ /* test the linked list */
+ g_assert(qemu_get_be64(f) == 44);
+ g_assert(qemu_get_be64(f) == 45);
+ g_assert(qemu_get_be64(f) == 46);
+ g_assert(qemu_get_be64(f) == 47);
+
+ qemu_fclose(f);
+ unlink(TEST_QEMU_FILE_PATH);
+}
+
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@@ -331,6 +733,8 @@ int main(int argc, char **argv)
g_test_add_func("/0.15/nested_structs", test_nested_structs);
g_test_add_func("/0.15/enums", test_enums);
g_test_add_func("/0.15/nested_enums", test_nested_enums);
+ g_test_add_func("/1.0/qemu_file_input_visitor", test_qemu_file_in_visitor);
+ g_test_add_func("/1.0/qemu_file_output_visitor",
test_qemu_file_out_visitor);
g_test_run();
--
1.7.4.1
- [Qemu-devel] [PATCH 00/10] do savevm/migration save/load via Visitor interface, Michael Roth, 2011/10/14
- [Qemu-devel] [PATCH 02/10] qapi: add QemuFileOutputVisitor, Michael Roth, 2011/10/14
- [Qemu-devel] [PATCH 03/10] qapi: add QemuFileInputVisitor, Michael Roth, 2011/10/14
- [Qemu-devel] [PATCH 01/10] qapi: add Visitor interfaces for uint*_t and int*_t, Michael Roth, 2011/10/14
- [Qemu-devel] [PATCH 04/10] savevm: move QEMUFile interfaces into qemu-file.c, Michael Roth, 2011/10/14
- [Qemu-devel] [PATCH 06/10] savevm: add QEMUFile->visitor lookup routines, Michael Roth, 2011/10/14
- [Qemu-devel] [PATCH 05/10] qapi: test cases for QEMUFile input/output visitors,
Michael Roth <=
- [Qemu-devel] [PATCH 08/10] trace: add trace statements for visitor interface, Michael Roth, 2011/10/14
- [Qemu-devel] [PATCH 09/10] qapi: add trace statements to qapi-visit-core.c, Michael Roth, 2011/10/14
- [Qemu-devel] [PATCH 07/10] trace: qemu_(put|get)_(byte|buffer) events, Michael Roth, 2011/10/14
- [Qemu-devel] [PATCH 10/10] vmstate: use visitors, Michael Roth, 2011/10/14