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 { 83*be1934dfSPaul Durrant XenstoreImplState *s = xs_impl_create(DOMID_GUEST); 843ef7ff83SDavid Woodhouse char *abspath; 85*be1934dfSPaul Durrant GList *perms; 863ef7ff83SDavid Woodhouse int err; 873ef7ff83SDavid Woodhouse 883ef7ff83SDavid Woodhouse abspath = g_strdup_printf("/local/domain/%u", DOMID_GUEST); 893ef7ff83SDavid Woodhouse 903ef7ff83SDavid Woodhouse err = write_str(s, DOMID_QEMU, XBT_NULL, abspath, ""); 913ef7ff83SDavid Woodhouse g_assert(!err); 926e133009SDavid Woodhouse g_assert(s->nr_nodes == 4); 933ef7ff83SDavid Woodhouse 94*be1934dfSPaul Durrant perms = g_list_append(NULL, g_strdup_printf("n%u", DOMID_QEMU)); 95*be1934dfSPaul Durrant perms = g_list_append(perms, g_strdup_printf("r%u", DOMID_GUEST)); 96*be1934dfSPaul Durrant 97*be1934dfSPaul Durrant err = xs_impl_set_perms(s, DOMID_QEMU, XBT_NULL, abspath, perms); 98*be1934dfSPaul Durrant g_assert(!err); 99*be1934dfSPaul Durrant 100*be1934dfSPaul Durrant g_list_free_full(perms, g_free); 1013ef7ff83SDavid Woodhouse g_free(abspath); 1023ef7ff83SDavid Woodhouse 1033ef7ff83SDavid Woodhouse abspath = g_strdup_printf("/local/domain/%u/some", DOMID_GUEST); 1043ef7ff83SDavid Woodhouse 1053ef7ff83SDavid Woodhouse err = write_str(s, DOMID_QEMU, XBT_NULL, abspath, ""); 1063ef7ff83SDavid Woodhouse g_assert(!err); 1073ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 5); 1083ef7ff83SDavid Woodhouse 109*be1934dfSPaul Durrant perms = g_list_append(NULL, g_strdup_printf("n%u", DOMID_GUEST)); 110*be1934dfSPaul Durrant 111*be1934dfSPaul Durrant err = xs_impl_set_perms(s, DOMID_QEMU, XBT_NULL, abspath, perms); 112*be1934dfSPaul Durrant g_assert(!err); 113*be1934dfSPaul Durrant 114*be1934dfSPaul Durrant g_list_free_full(perms, g_free); 1153ef7ff83SDavid Woodhouse g_free(abspath); 1163ef7ff83SDavid Woodhouse 1173ef7ff83SDavid Woodhouse return s; 1183ef7ff83SDavid Woodhouse } 1193ef7ff83SDavid Woodhouse 1203ef7ff83SDavid Woodhouse static void test_xs_node_simple(void) 1213ef7ff83SDavid Woodhouse { 1223ef7ff83SDavid Woodhouse GByteArray *data = g_byte_array_new(); 1233ef7ff83SDavid Woodhouse XenstoreImplState *s = setup(); 1246e133009SDavid Woodhouse GString *guest_watches = g_string_new(NULL); 1256e133009SDavid Woodhouse GString *qemu_watches = g_string_new(NULL); 1263ef7ff83SDavid Woodhouse GList *items = NULL; 1273ef7ff83SDavid Woodhouse XsNode *old_root; 1283ef7ff83SDavid Woodhouse uint64_t gencnt; 1293ef7ff83SDavid Woodhouse int err; 1303ef7ff83SDavid Woodhouse 1313ef7ff83SDavid Woodhouse g_assert(s); 1323ef7ff83SDavid Woodhouse 1336e133009SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "guestwatch", 1346e133009SDavid Woodhouse watch_cb, guest_watches); 1356e133009SDavid Woodhouse g_assert(!err); 1366e133009SDavid Woodhouse g_assert(guest_watches->len == strlen("someguestwatch")); 1376e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "someguestwatch")); 1386e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 1396e133009SDavid Woodhouse 1406e133009SDavid Woodhouse err = xs_impl_watch(s, 0, "/local/domain/1/some", "qemuwatch", 1416e133009SDavid Woodhouse watch_cb, qemu_watches); 1426e133009SDavid Woodhouse g_assert(!err); 1436e133009SDavid Woodhouse g_assert(qemu_watches->len == strlen("/local/domain/1/someqemuwatch")); 1446e133009SDavid Woodhouse g_assert(!strcmp(qemu_watches->str, "/local/domain/1/someqemuwatch")); 1456e133009SDavid Woodhouse g_string_truncate(qemu_watches, 0); 1466e133009SDavid Woodhouse 1473ef7ff83SDavid Woodhouse /* Read gives ENOENT when it should */ 1483ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "foo", data); 1493ef7ff83SDavid Woodhouse g_assert(err == ENOENT); 1503ef7ff83SDavid Woodhouse 1513ef7ff83SDavid Woodhouse /* Write works */ 1523ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 1533ef7ff83SDavid Woodhouse "something"); 1543ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 7); 1553ef7ff83SDavid Woodhouse g_assert(!err); 1566e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, 1576e133009SDavid Woodhouse "some/relative/pathguestwatch")); 1586e133009SDavid Woodhouse g_assert(!strcmp(qemu_watches->str, 1596e133009SDavid Woodhouse "/local/domain/1/some/relative/pathqemuwatch")); 1606e133009SDavid Woodhouse 1616e133009SDavid Woodhouse g_string_truncate(qemu_watches, 0); 1626e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 1636e133009SDavid Woodhouse xs_impl_reset_watches(s, 0); 1643ef7ff83SDavid Woodhouse 1653ef7ff83SDavid Woodhouse /* Read gives back what we wrote */ 1663ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", data); 1673ef7ff83SDavid Woodhouse g_assert(!err); 1683ef7ff83SDavid Woodhouse g_assert(data->len == strlen("something")); 1693ef7ff83SDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 1703ef7ff83SDavid Woodhouse 1713ef7ff83SDavid Woodhouse /* Even if we use an abolute path */ 1723ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 1733ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, 1743ef7ff83SDavid Woodhouse "/local/domain/1/some/relative/path", data); 1753ef7ff83SDavid Woodhouse g_assert(!err); 1763ef7ff83SDavid Woodhouse g_assert(data->len == strlen("something")); 1773ef7ff83SDavid Woodhouse 1786e133009SDavid Woodhouse g_assert(!qemu_watches->len); 1796e133009SDavid Woodhouse g_assert(!guest_watches->len); 1803ef7ff83SDavid Woodhouse /* Keep a copy, to force COW mode */ 1813ef7ff83SDavid Woodhouse old_root = xs_node_ref(s->root); 1823ef7ff83SDavid Woodhouse 183*be1934dfSPaul Durrant /* Write somewhere we aren't allowed, in COW mode */ 184*be1934dfSPaul Durrant err = write_str(s, DOMID_GUEST, XBT_NULL, "/local/domain/badplace", 185*be1934dfSPaul Durrant "moredata"); 186*be1934dfSPaul Durrant g_assert(err == EACCES); 187*be1934dfSPaul Durrant g_assert(s->nr_nodes == 7); 188*be1934dfSPaul Durrant 1893ef7ff83SDavid Woodhouse /* Write works again */ 1903ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, 1913ef7ff83SDavid Woodhouse "/local/domain/1/some/relative/path2", 1923ef7ff83SDavid Woodhouse "something else"); 1933ef7ff83SDavid Woodhouse g_assert(!err); 1943ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 8); 1956e133009SDavid Woodhouse g_assert(!qemu_watches->len); 1966e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "some/relative/path2guestwatch")); 1976e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 1983ef7ff83SDavid Woodhouse 1993ef7ff83SDavid Woodhouse /* Overwrite an existing node */ 2003ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 2013ef7ff83SDavid Woodhouse "another thing"); 2023ef7ff83SDavid Woodhouse g_assert(!err); 2033ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 8); 2046e133009SDavid Woodhouse g_assert(!qemu_watches->len); 2056e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "some/relative/pathguestwatch")); 2066e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 2073ef7ff83SDavid Woodhouse 2083ef7ff83SDavid Woodhouse /* We can list the two files we wrote */ 2093ef7ff83SDavid Woodhouse err = xs_impl_directory(s, DOMID_GUEST, XBT_NULL, "some/relative", &gencnt, 2103ef7ff83SDavid Woodhouse &items); 2113ef7ff83SDavid Woodhouse g_assert(!err); 2123ef7ff83SDavid Woodhouse g_assert(items); 2133ef7ff83SDavid Woodhouse g_assert(gencnt == 2); 2143ef7ff83SDavid Woodhouse g_assert(!strcmp(items->data, "path")); 2153ef7ff83SDavid Woodhouse g_assert(items->next); 2163ef7ff83SDavid Woodhouse g_assert(!strcmp(items->next->data, "path2")); 2173ef7ff83SDavid Woodhouse g_assert(!items->next->next); 2183ef7ff83SDavid Woodhouse g_list_free_full(items, g_free); 2193ef7ff83SDavid Woodhouse 2206e133009SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "guestwatch", 2216e133009SDavid Woodhouse watch_cb, guest_watches); 2226e133009SDavid Woodhouse g_assert(!err); 2236e133009SDavid Woodhouse 2246e133009SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "guestwatch", 2256e133009SDavid Woodhouse watch_cb, guest_watches); 2266e133009SDavid Woodhouse g_assert(err == ENOENT); 2276e133009SDavid Woodhouse 2286e133009SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some/relative/path2", "watchp2", 2296e133009SDavid Woodhouse watch_cb, guest_watches); 2306e133009SDavid Woodhouse g_assert(!err); 2316e133009SDavid Woodhouse g_assert(guest_watches->len == strlen("some/relative/path2watchp2")); 2326e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "some/relative/path2watchp2")); 2336e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 2346e133009SDavid Woodhouse 2356e133009SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "/local/domain/1/some/relative", 2366e133009SDavid Woodhouse "watchrel", watch_cb, guest_watches); 2376e133009SDavid Woodhouse g_assert(!err); 2386e133009SDavid Woodhouse g_assert(guest_watches->len == 2396e133009SDavid Woodhouse strlen("/local/domain/1/some/relativewatchrel")); 2406e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, 2416e133009SDavid Woodhouse "/local/domain/1/some/relativewatchrel")); 2426e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 2436e133009SDavid Woodhouse 2443ef7ff83SDavid Woodhouse /* Write somewhere else which already existed */ 2453ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative", "moredata"); 2463ef7ff83SDavid Woodhouse g_assert(!err); 2476e133009SDavid Woodhouse g_assert(s->nr_nodes == 8); 2486e133009SDavid Woodhouse 249*be1934dfSPaul Durrant /* Write somewhere we aren't allowed */ 250*be1934dfSPaul Durrant err = write_str(s, DOMID_GUEST, XBT_NULL, "/local/domain/badplace", 251*be1934dfSPaul Durrant "moredata"); 252*be1934dfSPaul Durrant g_assert(err == EACCES); 253*be1934dfSPaul Durrant 2546e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, 2556e133009SDavid Woodhouse "/local/domain/1/some/relativewatchrel")); 2566e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 2573ef7ff83SDavid Woodhouse 2583ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 2593ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); 2603ef7ff83SDavid Woodhouse g_assert(!err); 2613ef7ff83SDavid Woodhouse g_assert(data->len == strlen("moredata")); 2623ef7ff83SDavid Woodhouse g_assert(!memcmp(data->data, "moredata", data->len)); 2633ef7ff83SDavid Woodhouse 2643ef7ff83SDavid Woodhouse /* Overwrite existing data */ 2653ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative", "otherdata"); 2663ef7ff83SDavid Woodhouse g_assert(!err); 2676e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 2683ef7ff83SDavid Woodhouse 2693ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 2703ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); 2713ef7ff83SDavid Woodhouse g_assert(!err); 2723ef7ff83SDavid Woodhouse g_assert(data->len == strlen("otherdata")); 2733ef7ff83SDavid Woodhouse g_assert(!memcmp(data->data, "otherdata", data->len)); 2743ef7ff83SDavid Woodhouse 2753ef7ff83SDavid Woodhouse /* Remove the subtree */ 2763ef7ff83SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, XBT_NULL, "some/relative"); 2773ef7ff83SDavid Woodhouse g_assert(!err); 2783ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 5); 2793ef7ff83SDavid Woodhouse 2806e133009SDavid Woodhouse /* Each watch fires with the least specific relevant path */ 2816e133009SDavid Woodhouse g_assert(strstr(guest_watches->str, 2826e133009SDavid Woodhouse "some/relative/path2watchp2")); 2836e133009SDavid Woodhouse g_assert(strstr(guest_watches->str, 2846e133009SDavid Woodhouse "/local/domain/1/some/relativewatchrel")); 2856e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 2866e133009SDavid Woodhouse 2873ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 2883ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); 2893ef7ff83SDavid Woodhouse g_assert(err == ENOENT); 2903ef7ff83SDavid Woodhouse g_byte_array_unref(data); 2913ef7ff83SDavid Woodhouse 2926e133009SDavid Woodhouse xs_impl_reset_watches(s, DOMID_GUEST); 2936e133009SDavid Woodhouse g_string_free(qemu_watches, true); 2946e133009SDavid Woodhouse g_string_free(guest_watches, true); 2953ef7ff83SDavid Woodhouse xs_node_unref(old_root); 2963ef7ff83SDavid Woodhouse xs_impl_delete(s); 2973ef7ff83SDavid Woodhouse } 2983ef7ff83SDavid Woodhouse 2993ef7ff83SDavid Woodhouse 3007248b87cSDavid Woodhouse static void do_test_xs_node_tx(bool fail, bool commit) 3017248b87cSDavid Woodhouse { 3027248b87cSDavid Woodhouse XenstoreImplState *s = setup(); 3037248b87cSDavid Woodhouse GString *watches = g_string_new(NULL); 3047248b87cSDavid Woodhouse GByteArray *data = g_byte_array_new(); 3057248b87cSDavid Woodhouse unsigned int tx_id = XBT_NULL; 3067248b87cSDavid Woodhouse int err; 3077248b87cSDavid Woodhouse 3087248b87cSDavid Woodhouse g_assert(s); 3097248b87cSDavid Woodhouse 3107248b87cSDavid Woodhouse /* Set a watch */ 3117248b87cSDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 3127248b87cSDavid Woodhouse watch_cb, watches); 3137248b87cSDavid Woodhouse g_assert(!err); 3147248b87cSDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 3157248b87cSDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 3167248b87cSDavid Woodhouse g_string_truncate(watches, 0); 3177248b87cSDavid Woodhouse 3187248b87cSDavid Woodhouse /* Write something */ 3197248b87cSDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 3207248b87cSDavid Woodhouse "something"); 3217248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 3227248b87cSDavid Woodhouse g_assert(!err); 3237248b87cSDavid Woodhouse g_assert(!strcmp(watches->str, 3247248b87cSDavid Woodhouse "some/relative/pathwatch")); 3257248b87cSDavid Woodhouse g_string_truncate(watches, 0); 3267248b87cSDavid Woodhouse 3277248b87cSDavid Woodhouse /* Create a transaction */ 3287248b87cSDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 3297248b87cSDavid Woodhouse g_assert(!err); 3307248b87cSDavid Woodhouse 3317248b87cSDavid Woodhouse if (fail) { 3327248b87cSDavid Woodhouse /* Write something else in the root */ 3337248b87cSDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 3347248b87cSDavid Woodhouse "another thing"); 3357248b87cSDavid Woodhouse g_assert(!err); 3367248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 3377248b87cSDavid Woodhouse g_assert(!strcmp(watches->str, 3387248b87cSDavid Woodhouse "some/relative/pathwatch")); 3397248b87cSDavid Woodhouse g_string_truncate(watches, 0); 3407248b87cSDavid Woodhouse } 3417248b87cSDavid Woodhouse 3427248b87cSDavid Woodhouse g_assert(!watches->len); 3437248b87cSDavid Woodhouse 3447248b87cSDavid Woodhouse /* Perform a write in the transaction */ 3457248b87cSDavid Woodhouse err = write_str(s, DOMID_GUEST, tx_id, "some/relative/path", 3467248b87cSDavid Woodhouse "something else"); 3477248b87cSDavid Woodhouse g_assert(!err); 3487248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 3497248b87cSDavid Woodhouse g_assert(!watches->len); 3507248b87cSDavid Woodhouse 3517248b87cSDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", data); 3527248b87cSDavid Woodhouse g_assert(!err); 3537248b87cSDavid Woodhouse if (fail) { 3547248b87cSDavid Woodhouse g_assert(data->len == strlen("another thing")); 3557248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "another thing", data->len)); 3567248b87cSDavid Woodhouse } else { 3577248b87cSDavid Woodhouse g_assert(data->len == strlen("something")); 3587248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 3597248b87cSDavid Woodhouse } 3607248b87cSDavid Woodhouse g_byte_array_set_size(data, 0); 3617248b87cSDavid Woodhouse 3627248b87cSDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, tx_id, "some/relative/path", data); 3637248b87cSDavid Woodhouse g_assert(!err); 3647248b87cSDavid Woodhouse g_assert(data->len == strlen("something else")); 3657248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something else", data->len)); 3667248b87cSDavid Woodhouse g_byte_array_set_size(data, 0); 3677248b87cSDavid Woodhouse 3687248b87cSDavid Woodhouse /* Attempt to commit the transaction */ 3697248b87cSDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, commit); 3707248b87cSDavid Woodhouse if (commit && fail) { 3717248b87cSDavid Woodhouse g_assert(err == EAGAIN); 3727248b87cSDavid Woodhouse } else { 3737248b87cSDavid Woodhouse g_assert(!err); 3747248b87cSDavid Woodhouse } 3757cabbdb7SDavid Woodhouse if (commit && !fail) { 3767cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, 3777cabbdb7SDavid Woodhouse "some/relative/pathwatch")); 3787cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 3797cabbdb7SDavid Woodhouse } else { 3807248b87cSDavid Woodhouse g_assert(!watches->len); 3817cabbdb7SDavid Woodhouse } 3827248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 3837248b87cSDavid Woodhouse 3847248b87cSDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 3857248b87cSDavid Woodhouse watch_cb, watches); 3867248b87cSDavid Woodhouse g_assert(!err); 3877248b87cSDavid Woodhouse 3887248b87cSDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", data); 3897248b87cSDavid Woodhouse g_assert(!err); 3907248b87cSDavid Woodhouse if (fail) { 3917248b87cSDavid Woodhouse g_assert(data->len == strlen("another thing")); 3927248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "another thing", data->len)); 3937248b87cSDavid Woodhouse } else if (commit) { 3947248b87cSDavid Woodhouse g_assert(data->len == strlen("something else")); 3957248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something else", data->len)); 3967248b87cSDavid Woodhouse } else { 3977248b87cSDavid Woodhouse g_assert(data->len == strlen("something")); 3987248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 3997248b87cSDavid Woodhouse } 4007248b87cSDavid Woodhouse g_byte_array_unref(data); 4017248b87cSDavid Woodhouse g_string_free(watches, true); 4027248b87cSDavid Woodhouse xs_impl_delete(s); 4037248b87cSDavid Woodhouse } 4047248b87cSDavid Woodhouse 4057248b87cSDavid Woodhouse static void test_xs_node_tx_fail(void) 4067248b87cSDavid Woodhouse { 4077248b87cSDavid Woodhouse do_test_xs_node_tx(true, true); 4087248b87cSDavid Woodhouse } 4097248b87cSDavid Woodhouse 4107248b87cSDavid Woodhouse static void test_xs_node_tx_abort(void) 4117248b87cSDavid Woodhouse { 4127248b87cSDavid Woodhouse do_test_xs_node_tx(false, false); 4137248b87cSDavid Woodhouse do_test_xs_node_tx(true, false); 4147248b87cSDavid Woodhouse } 4157248b87cSDavid Woodhouse static void test_xs_node_tx_succeed(void) 4167248b87cSDavid Woodhouse { 4177248b87cSDavid Woodhouse do_test_xs_node_tx(false, true); 4187248b87cSDavid Woodhouse } 4197248b87cSDavid Woodhouse 4207cabbdb7SDavid Woodhouse static void test_xs_node_tx_rm(void) 4217cabbdb7SDavid Woodhouse { 4227cabbdb7SDavid Woodhouse XenstoreImplState *s = setup(); 4237cabbdb7SDavid Woodhouse GString *watches = g_string_new(NULL); 4247cabbdb7SDavid Woodhouse GByteArray *data = g_byte_array_new(); 4257cabbdb7SDavid Woodhouse unsigned int tx_id = XBT_NULL; 4267cabbdb7SDavid Woodhouse int err; 4277cabbdb7SDavid Woodhouse 4287cabbdb7SDavid Woodhouse g_assert(s); 4297cabbdb7SDavid Woodhouse 4307cabbdb7SDavid Woodhouse /* Set a watch */ 4317cabbdb7SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 4327cabbdb7SDavid Woodhouse watch_cb, watches); 4337cabbdb7SDavid Woodhouse g_assert(!err); 4347cabbdb7SDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 4357cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 4367cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 4377cabbdb7SDavid Woodhouse 4387cabbdb7SDavid Woodhouse /* Write something */ 4397cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 4407cabbdb7SDavid Woodhouse "something"); 4417cabbdb7SDavid Woodhouse g_assert(!err); 4427cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 4437cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, 4447cabbdb7SDavid Woodhouse "some/deep/dark/relative/pathwatch")); 4457cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 4467cabbdb7SDavid Woodhouse 4477cabbdb7SDavid Woodhouse /* Create a transaction */ 4487cabbdb7SDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 4497cabbdb7SDavid Woodhouse g_assert(!err); 4507cabbdb7SDavid Woodhouse 4517cabbdb7SDavid Woodhouse /* Delete the tree in the transaction */ 4527cabbdb7SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep/dark"); 4537cabbdb7SDavid Woodhouse g_assert(!err); 4547cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 4557cabbdb7SDavid Woodhouse g_assert(!watches->len); 4567cabbdb7SDavid Woodhouse 4577cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 4587cabbdb7SDavid Woodhouse data); 4597cabbdb7SDavid Woodhouse g_assert(!err); 4607cabbdb7SDavid Woodhouse g_assert(data->len == strlen("something")); 4617cabbdb7SDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 4627cabbdb7SDavid Woodhouse g_byte_array_set_size(data, 0); 4637cabbdb7SDavid Woodhouse 4647cabbdb7SDavid Woodhouse /* Commit the transaction */ 4657cabbdb7SDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); 4667cabbdb7SDavid Woodhouse g_assert(!err); 4677cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 6); 4687cabbdb7SDavid Woodhouse 4697cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "some/deep/darkwatch")); 4707cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 4717cabbdb7SDavid Woodhouse 4727cabbdb7SDavid Woodhouse /* Now the node is gone */ 4737cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 4747cabbdb7SDavid Woodhouse data); 4757cabbdb7SDavid Woodhouse g_assert(err == ENOENT); 4767cabbdb7SDavid Woodhouse g_byte_array_unref(data); 4777cabbdb7SDavid Woodhouse 4787cabbdb7SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 4797cabbdb7SDavid Woodhouse watch_cb, watches); 4807cabbdb7SDavid Woodhouse g_assert(!err); 4817cabbdb7SDavid Woodhouse 4827cabbdb7SDavid Woodhouse g_string_free(watches, true); 4837cabbdb7SDavid Woodhouse xs_impl_delete(s); 4847cabbdb7SDavid Woodhouse } 4857cabbdb7SDavid Woodhouse 4867cabbdb7SDavid Woodhouse static void test_xs_node_tx_resurrect(void) 4877cabbdb7SDavid Woodhouse { 4887cabbdb7SDavid Woodhouse XenstoreImplState *s = setup(); 4897cabbdb7SDavid Woodhouse GString *watches = g_string_new(NULL); 4907cabbdb7SDavid Woodhouse GByteArray *data = g_byte_array_new(); 4917cabbdb7SDavid Woodhouse unsigned int tx_id = XBT_NULL; 4927cabbdb7SDavid Woodhouse int err; 4937cabbdb7SDavid Woodhouse 4947cabbdb7SDavid Woodhouse g_assert(s); 4957cabbdb7SDavid Woodhouse 4967cabbdb7SDavid Woodhouse /* Write something */ 4977cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 4987cabbdb7SDavid Woodhouse "something"); 4997cabbdb7SDavid Woodhouse g_assert(!err); 5007cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 5017cabbdb7SDavid Woodhouse 5027cabbdb7SDavid Woodhouse /* This node will be wiped and resurrected */ 5037cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark", 5047cabbdb7SDavid Woodhouse "foo"); 5057cabbdb7SDavid Woodhouse g_assert(!err); 5067cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 5077cabbdb7SDavid Woodhouse 5087cabbdb7SDavid Woodhouse /* Set a watch */ 5097cabbdb7SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 5107cabbdb7SDavid Woodhouse watch_cb, watches); 5117cabbdb7SDavid Woodhouse g_assert(!err); 5127cabbdb7SDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 5137cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 5147cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 5157cabbdb7SDavid Woodhouse 5167cabbdb7SDavid Woodhouse /* Create a transaction */ 5177cabbdb7SDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 5187cabbdb7SDavid Woodhouse g_assert(!err); 5197cabbdb7SDavid Woodhouse 5207cabbdb7SDavid Woodhouse /* Delete the tree in the transaction */ 5217cabbdb7SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep"); 5227cabbdb7SDavid Woodhouse g_assert(!err); 5237cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 5247cabbdb7SDavid Woodhouse g_assert(!watches->len); 5257cabbdb7SDavid Woodhouse 5267cabbdb7SDavid Woodhouse /* Resurrect part of it */ 5277cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, tx_id, "some/deep/dark/different/path", 5287cabbdb7SDavid Woodhouse "something"); 5297cabbdb7SDavid Woodhouse g_assert(!err); 5307cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 5317cabbdb7SDavid Woodhouse 5327cabbdb7SDavid Woodhouse /* Commit the transaction */ 5337cabbdb7SDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); 5347cabbdb7SDavid Woodhouse g_assert(!err); 5357cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 5367cabbdb7SDavid Woodhouse 5377cabbdb7SDavid Woodhouse /* lost data */ 5387cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/dark/different/pathwatch")); 5397cabbdb7SDavid Woodhouse /* topmost deleted */ 5407cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/dark/relativewatch")); 5417cabbdb7SDavid Woodhouse /* lost data */ 5427cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/darkwatch")); 5437cabbdb7SDavid Woodhouse 5447cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 5457cabbdb7SDavid Woodhouse 5467cabbdb7SDavid Woodhouse /* Now the node is gone */ 5477cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 5487cabbdb7SDavid Woodhouse data); 5497cabbdb7SDavid Woodhouse g_assert(err == ENOENT); 5507cabbdb7SDavid Woodhouse g_byte_array_unref(data); 5517cabbdb7SDavid Woodhouse 5527cabbdb7SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 5537cabbdb7SDavid Woodhouse watch_cb, watches); 5547cabbdb7SDavid Woodhouse g_assert(!err); 5557cabbdb7SDavid Woodhouse 5567cabbdb7SDavid Woodhouse g_string_free(watches, true); 5577cabbdb7SDavid Woodhouse xs_impl_delete(s); 5587cabbdb7SDavid Woodhouse } 5597cabbdb7SDavid Woodhouse 5607cabbdb7SDavid Woodhouse static void test_xs_node_tx_resurrect2(void) 5617cabbdb7SDavid Woodhouse { 5627cabbdb7SDavid Woodhouse XenstoreImplState *s = setup(); 5637cabbdb7SDavid Woodhouse GString *watches = g_string_new(NULL); 5647cabbdb7SDavid Woodhouse GByteArray *data = g_byte_array_new(); 5657cabbdb7SDavid Woodhouse unsigned int tx_id = XBT_NULL; 5667cabbdb7SDavid Woodhouse int err; 5677cabbdb7SDavid Woodhouse 5687cabbdb7SDavid Woodhouse g_assert(s); 5697cabbdb7SDavid Woodhouse 5707cabbdb7SDavid Woodhouse /* Write something */ 5717cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 5727cabbdb7SDavid Woodhouse "something"); 5737cabbdb7SDavid Woodhouse g_assert(!err); 5747cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 5757cabbdb7SDavid Woodhouse 5767cabbdb7SDavid Woodhouse /* Another node to remain shared */ 5777cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/place/safe", "keepme"); 5787cabbdb7SDavid Woodhouse g_assert(!err); 5797cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 5807cabbdb7SDavid Woodhouse 5817cabbdb7SDavid Woodhouse /* This node will be wiped and resurrected */ 5827cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark", 5837cabbdb7SDavid Woodhouse "foo"); 5847cabbdb7SDavid Woodhouse g_assert(!err); 5857cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 5867cabbdb7SDavid Woodhouse 5877cabbdb7SDavid Woodhouse /* Set a watch */ 5887cabbdb7SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 5897cabbdb7SDavid Woodhouse watch_cb, watches); 5907cabbdb7SDavid Woodhouse g_assert(!err); 5917cabbdb7SDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 5927cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 5937cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 5947cabbdb7SDavid Woodhouse 5957cabbdb7SDavid Woodhouse /* Create a transaction */ 5967cabbdb7SDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 5977cabbdb7SDavid Woodhouse g_assert(!err); 5987cabbdb7SDavid Woodhouse 5997cabbdb7SDavid Woodhouse /* Delete the tree in the transaction */ 6007cabbdb7SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep"); 6017cabbdb7SDavid Woodhouse g_assert(!err); 6027cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 6037cabbdb7SDavid Woodhouse g_assert(!watches->len); 6047cabbdb7SDavid Woodhouse 6057cabbdb7SDavid Woodhouse /* Resurrect part of it */ 6067cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, tx_id, "some/deep/dark/relative/path", 6077cabbdb7SDavid Woodhouse "something"); 6087cabbdb7SDavid Woodhouse g_assert(!err); 6097cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 6107cabbdb7SDavid Woodhouse 6117cabbdb7SDavid Woodhouse /* Commit the transaction */ 6127cabbdb7SDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); 6137cabbdb7SDavid Woodhouse g_assert(!err); 6147cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 6157cabbdb7SDavid Woodhouse 6167cabbdb7SDavid Woodhouse /* lost data */ 6177cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/dark/relative/pathwatch")); 6187cabbdb7SDavid Woodhouse /* lost data */ 6197cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/darkwatch")); 6207cabbdb7SDavid Woodhouse 6217cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 6227cabbdb7SDavid Woodhouse 6237cabbdb7SDavid Woodhouse /* Now the node is gone */ 6247cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 6257cabbdb7SDavid Woodhouse data); 6267cabbdb7SDavid Woodhouse g_assert(!err); 6277cabbdb7SDavid Woodhouse g_assert(data->len == strlen("something")); 6287cabbdb7SDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 6297cabbdb7SDavid Woodhouse 6307cabbdb7SDavid Woodhouse g_byte_array_unref(data); 6317cabbdb7SDavid Woodhouse 6327cabbdb7SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 6337cabbdb7SDavid Woodhouse watch_cb, watches); 6347cabbdb7SDavid Woodhouse g_assert(!err); 6357cabbdb7SDavid Woodhouse 6367cabbdb7SDavid Woodhouse g_string_free(watches, true); 6377cabbdb7SDavid Woodhouse xs_impl_delete(s); 6387cabbdb7SDavid Woodhouse } 6397cabbdb7SDavid Woodhouse 6403ef7ff83SDavid Woodhouse int main(int argc, char **argv) 6413ef7ff83SDavid Woodhouse { 6423ef7ff83SDavid Woodhouse g_test_init(&argc, &argv, NULL); 6433ef7ff83SDavid Woodhouse module_call_init(MODULE_INIT_QOM); 6443ef7ff83SDavid Woodhouse 6453ef7ff83SDavid Woodhouse g_test_add_func("/xs_node/simple", test_xs_node_simple); 6467248b87cSDavid Woodhouse g_test_add_func("/xs_node/tx_abort", test_xs_node_tx_abort); 6477248b87cSDavid Woodhouse g_test_add_func("/xs_node/tx_fail", test_xs_node_tx_fail); 6487248b87cSDavid Woodhouse g_test_add_func("/xs_node/tx_succeed", test_xs_node_tx_succeed); 6497cabbdb7SDavid Woodhouse g_test_add_func("/xs_node/tx_rm", test_xs_node_tx_rm); 6507cabbdb7SDavid Woodhouse g_test_add_func("/xs_node/tx_resurrect", test_xs_node_tx_resurrect); 6517cabbdb7SDavid Woodhouse g_test_add_func("/xs_node/tx_resurrect2", test_xs_node_tx_resurrect2); 6523ef7ff83SDavid Woodhouse 6533ef7ff83SDavid Woodhouse return g_test_run(); 6543ef7ff83SDavid Woodhouse } 655