13ef7ff83SDavid Woodhouse /* 23ef7ff83SDavid Woodhouse * QEMU XenStore XsNode testing 33ef7ff83SDavid Woodhouse * 43ef7ff83SDavid Woodhouse * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. 53ef7ff83SDavid Woodhouse 63ef7ff83SDavid Woodhouse * This work is licensed under the terms of the GNU GPL, version 2 or later. 73ef7ff83SDavid Woodhouse * See the COPYING file in the top-level directory. 83ef7ff83SDavid Woodhouse */ 93ef7ff83SDavid Woodhouse 103ef7ff83SDavid Woodhouse #include "qemu/osdep.h" 113ef7ff83SDavid Woodhouse #include "qapi/error.h" 123ef7ff83SDavid Woodhouse #include "qemu/module.h" 133ef7ff83SDavid Woodhouse 143ef7ff83SDavid Woodhouse static int nr_xs_nodes; 153ef7ff83SDavid Woodhouse static GList *xs_node_list; 163ef7ff83SDavid Woodhouse 173ef7ff83SDavid Woodhouse #define XS_NODE_UNIT_TEST 183ef7ff83SDavid Woodhouse 193ef7ff83SDavid Woodhouse /* 203ef7ff83SDavid Woodhouse * We don't need the core Xen definitions. And we *do* want to be able 213ef7ff83SDavid Woodhouse * to run the unit tests even on architectures that Xen doesn't support 223ef7ff83SDavid Woodhouse * (because life's too short to bother doing otherwise, and test coverage 233ef7ff83SDavid Woodhouse * doesn't hurt). 243ef7ff83SDavid Woodhouse */ 253ef7ff83SDavid Woodhouse #define __XEN_PUBLIC_XEN_H__ 263ef7ff83SDavid Woodhouse 273ef7ff83SDavid Woodhouse #include "hw/i386/kvm/xenstore_impl.c" 283ef7ff83SDavid Woodhouse 293ef7ff83SDavid Woodhouse #define DOMID_QEMU 0 303ef7ff83SDavid Woodhouse #define DOMID_GUEST 1 313ef7ff83SDavid Woodhouse 323ef7ff83SDavid Woodhouse /* This doesn't happen in qemu but we want to make valgrind happy */ 333ef7ff83SDavid Woodhouse static void xs_impl_delete(XenstoreImplState *s) 343ef7ff83SDavid Woodhouse { 353ef7ff83SDavid Woodhouse int err; 363ef7ff83SDavid Woodhouse 376e133009SDavid Woodhouse xs_impl_reset_watches(s, DOMID_GUEST); 386e133009SDavid Woodhouse g_assert(!s->nr_domu_watches); 396e133009SDavid Woodhouse 403ef7ff83SDavid Woodhouse err = xs_impl_rm(s, DOMID_QEMU, XBT_NULL, "/local"); 413ef7ff83SDavid Woodhouse g_assert(!err); 423ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 1); 433ef7ff83SDavid Woodhouse 446e133009SDavid Woodhouse g_hash_table_unref(s->watches); 457248b87cSDavid Woodhouse g_hash_table_unref(s->transactions); 463ef7ff83SDavid Woodhouse xs_node_unref(s->root); 473ef7ff83SDavid Woodhouse g_free(s); 483ef7ff83SDavid Woodhouse 493ef7ff83SDavid Woodhouse if (xs_node_list) { 503ef7ff83SDavid Woodhouse GList *l; 513ef7ff83SDavid Woodhouse for (l = xs_node_list; l; l = l->next) { 523ef7ff83SDavid Woodhouse XsNode *n = l->data; 533ef7ff83SDavid Woodhouse printf("Remaining node at %p name %s ref %u\n", n, n->name, 543ef7ff83SDavid Woodhouse n->ref); 553ef7ff83SDavid Woodhouse } 563ef7ff83SDavid Woodhouse } 573ef7ff83SDavid Woodhouse g_assert(!nr_xs_nodes); 583ef7ff83SDavid Woodhouse } 593ef7ff83SDavid Woodhouse 603ef7ff83SDavid Woodhouse static int write_str(XenstoreImplState *s, unsigned int dom_id, 613ef7ff83SDavid Woodhouse unsigned int tx_id, const char *path, 623ef7ff83SDavid Woodhouse const char *content) 633ef7ff83SDavid Woodhouse { 643ef7ff83SDavid Woodhouse GByteArray *d = g_byte_array_new(); 653ef7ff83SDavid Woodhouse int err; 663ef7ff83SDavid Woodhouse 673ef7ff83SDavid Woodhouse g_byte_array_append(d, (void *)content, strlen(content)); 683ef7ff83SDavid Woodhouse err = xs_impl_write(s, dom_id, tx_id, path, d); 693ef7ff83SDavid Woodhouse g_byte_array_unref(d); 703ef7ff83SDavid Woodhouse return err; 713ef7ff83SDavid Woodhouse } 723ef7ff83SDavid Woodhouse 736e133009SDavid Woodhouse static void watch_cb(void *_str, const char *path, const char *token) 746e133009SDavid Woodhouse { 756e133009SDavid Woodhouse GString *str = _str; 766e133009SDavid Woodhouse 776e133009SDavid Woodhouse g_string_append(str, path); 786e133009SDavid Woodhouse g_string_append(str, token); 796e133009SDavid Woodhouse } 806e133009SDavid Woodhouse 813ef7ff83SDavid Woodhouse static XenstoreImplState *setup(void) 823ef7ff83SDavid Woodhouse { 833ef7ff83SDavid Woodhouse XenstoreImplState *s = xs_impl_create(); 843ef7ff83SDavid Woodhouse char *abspath; 853ef7ff83SDavid Woodhouse int err; 863ef7ff83SDavid Woodhouse 873ef7ff83SDavid Woodhouse abspath = g_strdup_printf("/local/domain/%u", DOMID_GUEST); 883ef7ff83SDavid Woodhouse 893ef7ff83SDavid Woodhouse err = write_str(s, DOMID_QEMU, XBT_NULL, abspath, ""); 903ef7ff83SDavid Woodhouse g_assert(!err); 916e133009SDavid Woodhouse g_assert(s->nr_nodes == 4); 923ef7ff83SDavid Woodhouse 933ef7ff83SDavid Woodhouse g_free(abspath); 943ef7ff83SDavid Woodhouse 953ef7ff83SDavid Woodhouse abspath = g_strdup_printf("/local/domain/%u/some", DOMID_GUEST); 963ef7ff83SDavid Woodhouse 973ef7ff83SDavid Woodhouse err = write_str(s, DOMID_QEMU, XBT_NULL, abspath, ""); 983ef7ff83SDavid Woodhouse g_assert(!err); 993ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 5); 1003ef7ff83SDavid Woodhouse 1013ef7ff83SDavid Woodhouse g_free(abspath); 1023ef7ff83SDavid Woodhouse 1033ef7ff83SDavid Woodhouse return s; 1043ef7ff83SDavid Woodhouse } 1053ef7ff83SDavid Woodhouse 1063ef7ff83SDavid Woodhouse static void test_xs_node_simple(void) 1073ef7ff83SDavid Woodhouse { 1083ef7ff83SDavid Woodhouse GByteArray *data = g_byte_array_new(); 1093ef7ff83SDavid Woodhouse XenstoreImplState *s = setup(); 1106e133009SDavid Woodhouse GString *guest_watches = g_string_new(NULL); 1116e133009SDavid Woodhouse GString *qemu_watches = g_string_new(NULL); 1123ef7ff83SDavid Woodhouse GList *items = NULL; 1133ef7ff83SDavid Woodhouse XsNode *old_root; 1143ef7ff83SDavid Woodhouse uint64_t gencnt; 1153ef7ff83SDavid Woodhouse int err; 1163ef7ff83SDavid Woodhouse 1173ef7ff83SDavid Woodhouse g_assert(s); 1183ef7ff83SDavid Woodhouse 1196e133009SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "guestwatch", 1206e133009SDavid Woodhouse watch_cb, guest_watches); 1216e133009SDavid Woodhouse g_assert(!err); 1226e133009SDavid Woodhouse g_assert(guest_watches->len == strlen("someguestwatch")); 1236e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "someguestwatch")); 1246e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 1256e133009SDavid Woodhouse 1266e133009SDavid Woodhouse err = xs_impl_watch(s, 0, "/local/domain/1/some", "qemuwatch", 1276e133009SDavid Woodhouse watch_cb, qemu_watches); 1286e133009SDavid Woodhouse g_assert(!err); 1296e133009SDavid Woodhouse g_assert(qemu_watches->len == strlen("/local/domain/1/someqemuwatch")); 1306e133009SDavid Woodhouse g_assert(!strcmp(qemu_watches->str, "/local/domain/1/someqemuwatch")); 1316e133009SDavid Woodhouse g_string_truncate(qemu_watches, 0); 1326e133009SDavid Woodhouse 1333ef7ff83SDavid Woodhouse /* Read gives ENOENT when it should */ 1343ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "foo", data); 1353ef7ff83SDavid Woodhouse g_assert(err == ENOENT); 1363ef7ff83SDavid Woodhouse 1373ef7ff83SDavid Woodhouse /* Write works */ 1383ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 1393ef7ff83SDavid Woodhouse "something"); 1403ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 7); 1413ef7ff83SDavid Woodhouse g_assert(!err); 1426e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, 1436e133009SDavid Woodhouse "some/relative/pathguestwatch")); 1446e133009SDavid Woodhouse g_assert(!strcmp(qemu_watches->str, 1456e133009SDavid Woodhouse "/local/domain/1/some/relative/pathqemuwatch")); 1466e133009SDavid Woodhouse 1476e133009SDavid Woodhouse g_string_truncate(qemu_watches, 0); 1486e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 1496e133009SDavid Woodhouse xs_impl_reset_watches(s, 0); 1503ef7ff83SDavid Woodhouse 1513ef7ff83SDavid Woodhouse /* Read gives back what we wrote */ 1523ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", data); 1533ef7ff83SDavid Woodhouse g_assert(!err); 1543ef7ff83SDavid Woodhouse g_assert(data->len == strlen("something")); 1553ef7ff83SDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 1563ef7ff83SDavid Woodhouse 1573ef7ff83SDavid Woodhouse /* Even if we use an abolute path */ 1583ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 1593ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, 1603ef7ff83SDavid Woodhouse "/local/domain/1/some/relative/path", data); 1613ef7ff83SDavid Woodhouse g_assert(!err); 1623ef7ff83SDavid Woodhouse g_assert(data->len == strlen("something")); 1633ef7ff83SDavid Woodhouse 1646e133009SDavid Woodhouse g_assert(!qemu_watches->len); 1656e133009SDavid Woodhouse g_assert(!guest_watches->len); 1663ef7ff83SDavid Woodhouse /* Keep a copy, to force COW mode */ 1673ef7ff83SDavid Woodhouse old_root = xs_node_ref(s->root); 1683ef7ff83SDavid Woodhouse 1693ef7ff83SDavid Woodhouse /* Write works again */ 1703ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, 1713ef7ff83SDavid Woodhouse "/local/domain/1/some/relative/path2", 1723ef7ff83SDavid Woodhouse "something else"); 1733ef7ff83SDavid Woodhouse g_assert(!err); 1743ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 8); 1756e133009SDavid Woodhouse g_assert(!qemu_watches->len); 1766e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "some/relative/path2guestwatch")); 1776e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 1783ef7ff83SDavid Woodhouse 1793ef7ff83SDavid Woodhouse /* Overwrite an existing node */ 1803ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 1813ef7ff83SDavid Woodhouse "another thing"); 1823ef7ff83SDavid Woodhouse g_assert(!err); 1833ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 8); 1846e133009SDavid Woodhouse g_assert(!qemu_watches->len); 1856e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "some/relative/pathguestwatch")); 1866e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 1873ef7ff83SDavid Woodhouse 1883ef7ff83SDavid Woodhouse /* We can list the two files we wrote */ 1893ef7ff83SDavid Woodhouse err = xs_impl_directory(s, DOMID_GUEST, XBT_NULL, "some/relative", &gencnt, 1903ef7ff83SDavid Woodhouse &items); 1913ef7ff83SDavid Woodhouse g_assert(!err); 1923ef7ff83SDavid Woodhouse g_assert(items); 1933ef7ff83SDavid Woodhouse g_assert(gencnt == 2); 1943ef7ff83SDavid Woodhouse g_assert(!strcmp(items->data, "path")); 1953ef7ff83SDavid Woodhouse g_assert(items->next); 1963ef7ff83SDavid Woodhouse g_assert(!strcmp(items->next->data, "path2")); 1973ef7ff83SDavid Woodhouse g_assert(!items->next->next); 1983ef7ff83SDavid Woodhouse g_list_free_full(items, g_free); 1993ef7ff83SDavid Woodhouse 2006e133009SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "guestwatch", 2016e133009SDavid Woodhouse watch_cb, guest_watches); 2026e133009SDavid Woodhouse g_assert(!err); 2036e133009SDavid Woodhouse 2046e133009SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "guestwatch", 2056e133009SDavid Woodhouse watch_cb, guest_watches); 2066e133009SDavid Woodhouse g_assert(err == ENOENT); 2076e133009SDavid Woodhouse 2086e133009SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some/relative/path2", "watchp2", 2096e133009SDavid Woodhouse watch_cb, guest_watches); 2106e133009SDavid Woodhouse g_assert(!err); 2116e133009SDavid Woodhouse g_assert(guest_watches->len == strlen("some/relative/path2watchp2")); 2126e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "some/relative/path2watchp2")); 2136e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 2146e133009SDavid Woodhouse 2156e133009SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "/local/domain/1/some/relative", 2166e133009SDavid Woodhouse "watchrel", watch_cb, guest_watches); 2176e133009SDavid Woodhouse g_assert(!err); 2186e133009SDavid Woodhouse g_assert(guest_watches->len == 2196e133009SDavid Woodhouse strlen("/local/domain/1/some/relativewatchrel")); 2206e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, 2216e133009SDavid Woodhouse "/local/domain/1/some/relativewatchrel")); 2226e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 2236e133009SDavid Woodhouse 2243ef7ff83SDavid Woodhouse /* Write somewhere else which already existed */ 2253ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative", "moredata"); 2263ef7ff83SDavid Woodhouse g_assert(!err); 2276e133009SDavid Woodhouse g_assert(s->nr_nodes == 8); 2286e133009SDavid Woodhouse 2296e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, 2306e133009SDavid Woodhouse "/local/domain/1/some/relativewatchrel")); 2316e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 2323ef7ff83SDavid Woodhouse 2333ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 2343ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); 2353ef7ff83SDavid Woodhouse g_assert(!err); 2363ef7ff83SDavid Woodhouse g_assert(data->len == strlen("moredata")); 2373ef7ff83SDavid Woodhouse g_assert(!memcmp(data->data, "moredata", data->len)); 2383ef7ff83SDavid Woodhouse 2393ef7ff83SDavid Woodhouse /* Overwrite existing data */ 2403ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative", "otherdata"); 2413ef7ff83SDavid Woodhouse g_assert(!err); 2426e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 2433ef7ff83SDavid Woodhouse 2443ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 2453ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); 2463ef7ff83SDavid Woodhouse g_assert(!err); 2473ef7ff83SDavid Woodhouse g_assert(data->len == strlen("otherdata")); 2483ef7ff83SDavid Woodhouse g_assert(!memcmp(data->data, "otherdata", data->len)); 2493ef7ff83SDavid Woodhouse 2503ef7ff83SDavid Woodhouse /* Remove the subtree */ 2513ef7ff83SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, XBT_NULL, "some/relative"); 2523ef7ff83SDavid Woodhouse g_assert(!err); 2533ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 5); 2543ef7ff83SDavid Woodhouse 2556e133009SDavid Woodhouse /* Each watch fires with the least specific relevant path */ 2566e133009SDavid Woodhouse g_assert(strstr(guest_watches->str, 2576e133009SDavid Woodhouse "some/relative/path2watchp2")); 2586e133009SDavid Woodhouse g_assert(strstr(guest_watches->str, 2596e133009SDavid Woodhouse "/local/domain/1/some/relativewatchrel")); 2606e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 2616e133009SDavid Woodhouse 2623ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 2633ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); 2643ef7ff83SDavid Woodhouse g_assert(err == ENOENT); 2653ef7ff83SDavid Woodhouse g_byte_array_unref(data); 2663ef7ff83SDavid Woodhouse 2676e133009SDavid Woodhouse xs_impl_reset_watches(s, DOMID_GUEST); 2686e133009SDavid Woodhouse g_string_free(qemu_watches, true); 2696e133009SDavid Woodhouse g_string_free(guest_watches, true); 2703ef7ff83SDavid Woodhouse xs_node_unref(old_root); 2713ef7ff83SDavid Woodhouse xs_impl_delete(s); 2723ef7ff83SDavid Woodhouse } 2733ef7ff83SDavid Woodhouse 2743ef7ff83SDavid Woodhouse 2757248b87cSDavid Woodhouse static void do_test_xs_node_tx(bool fail, bool commit) 2767248b87cSDavid Woodhouse { 2777248b87cSDavid Woodhouse XenstoreImplState *s = setup(); 2787248b87cSDavid Woodhouse GString *watches = g_string_new(NULL); 2797248b87cSDavid Woodhouse GByteArray *data = g_byte_array_new(); 2807248b87cSDavid Woodhouse unsigned int tx_id = XBT_NULL; 2817248b87cSDavid Woodhouse int err; 2827248b87cSDavid Woodhouse 2837248b87cSDavid Woodhouse g_assert(s); 2847248b87cSDavid Woodhouse 2857248b87cSDavid Woodhouse /* Set a watch */ 2867248b87cSDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 2877248b87cSDavid Woodhouse watch_cb, watches); 2887248b87cSDavid Woodhouse g_assert(!err); 2897248b87cSDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 2907248b87cSDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 2917248b87cSDavid Woodhouse g_string_truncate(watches, 0); 2927248b87cSDavid Woodhouse 2937248b87cSDavid Woodhouse /* Write something */ 2947248b87cSDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 2957248b87cSDavid Woodhouse "something"); 2967248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 2977248b87cSDavid Woodhouse g_assert(!err); 2987248b87cSDavid Woodhouse g_assert(!strcmp(watches->str, 2997248b87cSDavid Woodhouse "some/relative/pathwatch")); 3007248b87cSDavid Woodhouse g_string_truncate(watches, 0); 3017248b87cSDavid Woodhouse 3027248b87cSDavid Woodhouse /* Create a transaction */ 3037248b87cSDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 3047248b87cSDavid Woodhouse g_assert(!err); 3057248b87cSDavid Woodhouse 3067248b87cSDavid Woodhouse if (fail) { 3077248b87cSDavid Woodhouse /* Write something else in the root */ 3087248b87cSDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 3097248b87cSDavid Woodhouse "another thing"); 3107248b87cSDavid Woodhouse g_assert(!err); 3117248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 3127248b87cSDavid Woodhouse g_assert(!strcmp(watches->str, 3137248b87cSDavid Woodhouse "some/relative/pathwatch")); 3147248b87cSDavid Woodhouse g_string_truncate(watches, 0); 3157248b87cSDavid Woodhouse } 3167248b87cSDavid Woodhouse 3177248b87cSDavid Woodhouse g_assert(!watches->len); 3187248b87cSDavid Woodhouse 3197248b87cSDavid Woodhouse /* Perform a write in the transaction */ 3207248b87cSDavid Woodhouse err = write_str(s, DOMID_GUEST, tx_id, "some/relative/path", 3217248b87cSDavid Woodhouse "something else"); 3227248b87cSDavid Woodhouse g_assert(!err); 3237248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 3247248b87cSDavid Woodhouse g_assert(!watches->len); 3257248b87cSDavid Woodhouse 3267248b87cSDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", data); 3277248b87cSDavid Woodhouse g_assert(!err); 3287248b87cSDavid Woodhouse if (fail) { 3297248b87cSDavid Woodhouse g_assert(data->len == strlen("another thing")); 3307248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "another thing", data->len)); 3317248b87cSDavid Woodhouse } else { 3327248b87cSDavid Woodhouse g_assert(data->len == strlen("something")); 3337248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 3347248b87cSDavid Woodhouse } 3357248b87cSDavid Woodhouse g_byte_array_set_size(data, 0); 3367248b87cSDavid Woodhouse 3377248b87cSDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, tx_id, "some/relative/path", data); 3387248b87cSDavid Woodhouse g_assert(!err); 3397248b87cSDavid Woodhouse g_assert(data->len == strlen("something else")); 3407248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something else", data->len)); 3417248b87cSDavid Woodhouse g_byte_array_set_size(data, 0); 3427248b87cSDavid Woodhouse 3437248b87cSDavid Woodhouse /* Attempt to commit the transaction */ 3447248b87cSDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, commit); 3457248b87cSDavid Woodhouse if (commit && fail) { 3467248b87cSDavid Woodhouse g_assert(err == EAGAIN); 3477248b87cSDavid Woodhouse } else { 3487248b87cSDavid Woodhouse g_assert(!err); 3497248b87cSDavid Woodhouse } 350*7cabbdb7SDavid Woodhouse if (commit && !fail) { 351*7cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, 352*7cabbdb7SDavid Woodhouse "some/relative/pathwatch")); 353*7cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 354*7cabbdb7SDavid Woodhouse } else { 3557248b87cSDavid Woodhouse g_assert(!watches->len); 356*7cabbdb7SDavid Woodhouse } 3577248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 3587248b87cSDavid Woodhouse 3597248b87cSDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 3607248b87cSDavid Woodhouse watch_cb, watches); 3617248b87cSDavid Woodhouse g_assert(!err); 3627248b87cSDavid Woodhouse 3637248b87cSDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", data); 3647248b87cSDavid Woodhouse g_assert(!err); 3657248b87cSDavid Woodhouse if (fail) { 3667248b87cSDavid Woodhouse g_assert(data->len == strlen("another thing")); 3677248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "another thing", data->len)); 3687248b87cSDavid Woodhouse } else if (commit) { 3697248b87cSDavid Woodhouse g_assert(data->len == strlen("something else")); 3707248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something else", data->len)); 3717248b87cSDavid Woodhouse } else { 3727248b87cSDavid Woodhouse g_assert(data->len == strlen("something")); 3737248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 3747248b87cSDavid Woodhouse } 3757248b87cSDavid Woodhouse g_byte_array_unref(data); 3767248b87cSDavid Woodhouse g_string_free(watches, true); 3777248b87cSDavid Woodhouse xs_impl_delete(s); 3787248b87cSDavid Woodhouse } 3797248b87cSDavid Woodhouse 3807248b87cSDavid Woodhouse static void test_xs_node_tx_fail(void) 3817248b87cSDavid Woodhouse { 3827248b87cSDavid Woodhouse do_test_xs_node_tx(true, true); 3837248b87cSDavid Woodhouse } 3847248b87cSDavid Woodhouse 3857248b87cSDavid Woodhouse static void test_xs_node_tx_abort(void) 3867248b87cSDavid Woodhouse { 3877248b87cSDavid Woodhouse do_test_xs_node_tx(false, false); 3887248b87cSDavid Woodhouse do_test_xs_node_tx(true, false); 3897248b87cSDavid Woodhouse } 3907248b87cSDavid Woodhouse static void test_xs_node_tx_succeed(void) 3917248b87cSDavid Woodhouse { 3927248b87cSDavid Woodhouse do_test_xs_node_tx(false, true); 3937248b87cSDavid Woodhouse } 3947248b87cSDavid Woodhouse 395*7cabbdb7SDavid Woodhouse static void test_xs_node_tx_rm(void) 396*7cabbdb7SDavid Woodhouse { 397*7cabbdb7SDavid Woodhouse XenstoreImplState *s = setup(); 398*7cabbdb7SDavid Woodhouse GString *watches = g_string_new(NULL); 399*7cabbdb7SDavid Woodhouse GByteArray *data = g_byte_array_new(); 400*7cabbdb7SDavid Woodhouse unsigned int tx_id = XBT_NULL; 401*7cabbdb7SDavid Woodhouse int err; 402*7cabbdb7SDavid Woodhouse 403*7cabbdb7SDavid Woodhouse g_assert(s); 404*7cabbdb7SDavid Woodhouse 405*7cabbdb7SDavid Woodhouse /* Set a watch */ 406*7cabbdb7SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 407*7cabbdb7SDavid Woodhouse watch_cb, watches); 408*7cabbdb7SDavid Woodhouse g_assert(!err); 409*7cabbdb7SDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 410*7cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 411*7cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 412*7cabbdb7SDavid Woodhouse 413*7cabbdb7SDavid Woodhouse /* Write something */ 414*7cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 415*7cabbdb7SDavid Woodhouse "something"); 416*7cabbdb7SDavid Woodhouse g_assert(!err); 417*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 418*7cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, 419*7cabbdb7SDavid Woodhouse "some/deep/dark/relative/pathwatch")); 420*7cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 421*7cabbdb7SDavid Woodhouse 422*7cabbdb7SDavid Woodhouse /* Create a transaction */ 423*7cabbdb7SDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 424*7cabbdb7SDavid Woodhouse g_assert(!err); 425*7cabbdb7SDavid Woodhouse 426*7cabbdb7SDavid Woodhouse /* Delete the tree in the transaction */ 427*7cabbdb7SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep/dark"); 428*7cabbdb7SDavid Woodhouse g_assert(!err); 429*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 430*7cabbdb7SDavid Woodhouse g_assert(!watches->len); 431*7cabbdb7SDavid Woodhouse 432*7cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 433*7cabbdb7SDavid Woodhouse data); 434*7cabbdb7SDavid Woodhouse g_assert(!err); 435*7cabbdb7SDavid Woodhouse g_assert(data->len == strlen("something")); 436*7cabbdb7SDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 437*7cabbdb7SDavid Woodhouse g_byte_array_set_size(data, 0); 438*7cabbdb7SDavid Woodhouse 439*7cabbdb7SDavid Woodhouse /* Commit the transaction */ 440*7cabbdb7SDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); 441*7cabbdb7SDavid Woodhouse g_assert(!err); 442*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 6); 443*7cabbdb7SDavid Woodhouse 444*7cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "some/deep/darkwatch")); 445*7cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 446*7cabbdb7SDavid Woodhouse 447*7cabbdb7SDavid Woodhouse /* Now the node is gone */ 448*7cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 449*7cabbdb7SDavid Woodhouse data); 450*7cabbdb7SDavid Woodhouse g_assert(err == ENOENT); 451*7cabbdb7SDavid Woodhouse g_byte_array_unref(data); 452*7cabbdb7SDavid Woodhouse 453*7cabbdb7SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 454*7cabbdb7SDavid Woodhouse watch_cb, watches); 455*7cabbdb7SDavid Woodhouse g_assert(!err); 456*7cabbdb7SDavid Woodhouse 457*7cabbdb7SDavid Woodhouse g_string_free(watches, true); 458*7cabbdb7SDavid Woodhouse xs_impl_delete(s); 459*7cabbdb7SDavid Woodhouse } 460*7cabbdb7SDavid Woodhouse 461*7cabbdb7SDavid Woodhouse static void test_xs_node_tx_resurrect(void) 462*7cabbdb7SDavid Woodhouse { 463*7cabbdb7SDavid Woodhouse XenstoreImplState *s = setup(); 464*7cabbdb7SDavid Woodhouse GString *watches = g_string_new(NULL); 465*7cabbdb7SDavid Woodhouse GByteArray *data = g_byte_array_new(); 466*7cabbdb7SDavid Woodhouse unsigned int tx_id = XBT_NULL; 467*7cabbdb7SDavid Woodhouse int err; 468*7cabbdb7SDavid Woodhouse 469*7cabbdb7SDavid Woodhouse g_assert(s); 470*7cabbdb7SDavid Woodhouse 471*7cabbdb7SDavid Woodhouse /* Write something */ 472*7cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 473*7cabbdb7SDavid Woodhouse "something"); 474*7cabbdb7SDavid Woodhouse g_assert(!err); 475*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 476*7cabbdb7SDavid Woodhouse 477*7cabbdb7SDavid Woodhouse /* This node will be wiped and resurrected */ 478*7cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark", 479*7cabbdb7SDavid Woodhouse "foo"); 480*7cabbdb7SDavid Woodhouse g_assert(!err); 481*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 482*7cabbdb7SDavid Woodhouse 483*7cabbdb7SDavid Woodhouse /* Set a watch */ 484*7cabbdb7SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 485*7cabbdb7SDavid Woodhouse watch_cb, watches); 486*7cabbdb7SDavid Woodhouse g_assert(!err); 487*7cabbdb7SDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 488*7cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 489*7cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 490*7cabbdb7SDavid Woodhouse 491*7cabbdb7SDavid Woodhouse /* Create a transaction */ 492*7cabbdb7SDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 493*7cabbdb7SDavid Woodhouse g_assert(!err); 494*7cabbdb7SDavid Woodhouse 495*7cabbdb7SDavid Woodhouse /* Delete the tree in the transaction */ 496*7cabbdb7SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep"); 497*7cabbdb7SDavid Woodhouse g_assert(!err); 498*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 499*7cabbdb7SDavid Woodhouse g_assert(!watches->len); 500*7cabbdb7SDavid Woodhouse 501*7cabbdb7SDavid Woodhouse /* Resurrect part of it */ 502*7cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, tx_id, "some/deep/dark/different/path", 503*7cabbdb7SDavid Woodhouse "something"); 504*7cabbdb7SDavid Woodhouse g_assert(!err); 505*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 506*7cabbdb7SDavid Woodhouse 507*7cabbdb7SDavid Woodhouse /* Commit the transaction */ 508*7cabbdb7SDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); 509*7cabbdb7SDavid Woodhouse g_assert(!err); 510*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 511*7cabbdb7SDavid Woodhouse 512*7cabbdb7SDavid Woodhouse /* lost data */ 513*7cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/dark/different/pathwatch")); 514*7cabbdb7SDavid Woodhouse /* topmost deleted */ 515*7cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/dark/relativewatch")); 516*7cabbdb7SDavid Woodhouse /* lost data */ 517*7cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/darkwatch")); 518*7cabbdb7SDavid Woodhouse 519*7cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 520*7cabbdb7SDavid Woodhouse 521*7cabbdb7SDavid Woodhouse /* Now the node is gone */ 522*7cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 523*7cabbdb7SDavid Woodhouse data); 524*7cabbdb7SDavid Woodhouse g_assert(err == ENOENT); 525*7cabbdb7SDavid Woodhouse g_byte_array_unref(data); 526*7cabbdb7SDavid Woodhouse 527*7cabbdb7SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 528*7cabbdb7SDavid Woodhouse watch_cb, watches); 529*7cabbdb7SDavid Woodhouse g_assert(!err); 530*7cabbdb7SDavid Woodhouse 531*7cabbdb7SDavid Woodhouse g_string_free(watches, true); 532*7cabbdb7SDavid Woodhouse xs_impl_delete(s); 533*7cabbdb7SDavid Woodhouse } 534*7cabbdb7SDavid Woodhouse 535*7cabbdb7SDavid Woodhouse static void test_xs_node_tx_resurrect2(void) 536*7cabbdb7SDavid Woodhouse { 537*7cabbdb7SDavid Woodhouse XenstoreImplState *s = setup(); 538*7cabbdb7SDavid Woodhouse GString *watches = g_string_new(NULL); 539*7cabbdb7SDavid Woodhouse GByteArray *data = g_byte_array_new(); 540*7cabbdb7SDavid Woodhouse unsigned int tx_id = XBT_NULL; 541*7cabbdb7SDavid Woodhouse int err; 542*7cabbdb7SDavid Woodhouse 543*7cabbdb7SDavid Woodhouse g_assert(s); 544*7cabbdb7SDavid Woodhouse 545*7cabbdb7SDavid Woodhouse /* Write something */ 546*7cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 547*7cabbdb7SDavid Woodhouse "something"); 548*7cabbdb7SDavid Woodhouse g_assert(!err); 549*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 550*7cabbdb7SDavid Woodhouse 551*7cabbdb7SDavid Woodhouse /* Another node to remain shared */ 552*7cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/place/safe", "keepme"); 553*7cabbdb7SDavid Woodhouse g_assert(!err); 554*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 555*7cabbdb7SDavid Woodhouse 556*7cabbdb7SDavid Woodhouse /* This node will be wiped and resurrected */ 557*7cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark", 558*7cabbdb7SDavid Woodhouse "foo"); 559*7cabbdb7SDavid Woodhouse g_assert(!err); 560*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 561*7cabbdb7SDavid Woodhouse 562*7cabbdb7SDavid Woodhouse /* Set a watch */ 563*7cabbdb7SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 564*7cabbdb7SDavid Woodhouse watch_cb, watches); 565*7cabbdb7SDavid Woodhouse g_assert(!err); 566*7cabbdb7SDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 567*7cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 568*7cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 569*7cabbdb7SDavid Woodhouse 570*7cabbdb7SDavid Woodhouse /* Create a transaction */ 571*7cabbdb7SDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 572*7cabbdb7SDavid Woodhouse g_assert(!err); 573*7cabbdb7SDavid Woodhouse 574*7cabbdb7SDavid Woodhouse /* Delete the tree in the transaction */ 575*7cabbdb7SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep"); 576*7cabbdb7SDavid Woodhouse g_assert(!err); 577*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 578*7cabbdb7SDavid Woodhouse g_assert(!watches->len); 579*7cabbdb7SDavid Woodhouse 580*7cabbdb7SDavid Woodhouse /* Resurrect part of it */ 581*7cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, tx_id, "some/deep/dark/relative/path", 582*7cabbdb7SDavid Woodhouse "something"); 583*7cabbdb7SDavid Woodhouse g_assert(!err); 584*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 585*7cabbdb7SDavid Woodhouse 586*7cabbdb7SDavid Woodhouse /* Commit the transaction */ 587*7cabbdb7SDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); 588*7cabbdb7SDavid Woodhouse g_assert(!err); 589*7cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 590*7cabbdb7SDavid Woodhouse 591*7cabbdb7SDavid Woodhouse /* lost data */ 592*7cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/dark/relative/pathwatch")); 593*7cabbdb7SDavid Woodhouse /* lost data */ 594*7cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/darkwatch")); 595*7cabbdb7SDavid Woodhouse 596*7cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 597*7cabbdb7SDavid Woodhouse 598*7cabbdb7SDavid Woodhouse /* Now the node is gone */ 599*7cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 600*7cabbdb7SDavid Woodhouse data); 601*7cabbdb7SDavid Woodhouse g_assert(!err); 602*7cabbdb7SDavid Woodhouse g_assert(data->len == strlen("something")); 603*7cabbdb7SDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 604*7cabbdb7SDavid Woodhouse 605*7cabbdb7SDavid Woodhouse g_byte_array_unref(data); 606*7cabbdb7SDavid Woodhouse 607*7cabbdb7SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 608*7cabbdb7SDavid Woodhouse watch_cb, watches); 609*7cabbdb7SDavid Woodhouse g_assert(!err); 610*7cabbdb7SDavid Woodhouse 611*7cabbdb7SDavid Woodhouse g_string_free(watches, true); 612*7cabbdb7SDavid Woodhouse xs_impl_delete(s); 613*7cabbdb7SDavid Woodhouse } 614*7cabbdb7SDavid Woodhouse 6153ef7ff83SDavid Woodhouse int main(int argc, char **argv) 6163ef7ff83SDavid Woodhouse { 6173ef7ff83SDavid Woodhouse g_test_init(&argc, &argv, NULL); 6183ef7ff83SDavid Woodhouse module_call_init(MODULE_INIT_QOM); 6193ef7ff83SDavid Woodhouse 6203ef7ff83SDavid Woodhouse g_test_add_func("/xs_node/simple", test_xs_node_simple); 6217248b87cSDavid Woodhouse g_test_add_func("/xs_node/tx_abort", test_xs_node_tx_abort); 6227248b87cSDavid Woodhouse g_test_add_func("/xs_node/tx_fail", test_xs_node_tx_fail); 6237248b87cSDavid Woodhouse g_test_add_func("/xs_node/tx_succeed", test_xs_node_tx_succeed); 624*7cabbdb7SDavid Woodhouse g_test_add_func("/xs_node/tx_rm", test_xs_node_tx_rm); 625*7cabbdb7SDavid Woodhouse g_test_add_func("/xs_node/tx_resurrect", test_xs_node_tx_resurrect); 626*7cabbdb7SDavid Woodhouse g_test_add_func("/xs_node/tx_resurrect2", test_xs_node_tx_resurrect2); 6273ef7ff83SDavid Woodhouse 6283ef7ff83SDavid Woodhouse return g_test_run(); 6293ef7ff83SDavid Woodhouse } 630