aboutsummaryrefslogtreecommitdiff
path: root/test/unit-tests.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/unit-tests.c')
-rw-r--r--test/unit-tests.c160
1 files changed, 156 insertions, 4 deletions
diff --git a/test/unit-tests.c b/test/unit-tests.c
index 19375b8..c09c8a9 100644
--- a/test/unit-tests.c
+++ b/test/unit-tests.c
@@ -37,10 +37,13 @@
#include <stdio.h>
#include <assert.h>
#include <alloca.h>
+#include <string.h>
#include "dma.h"
#include "libvfio-user.h"
#include "private.h"
+#include "migration.h"
+#include "tran_sock.h"
static void
test_dma_map_without_dma(void **state __attribute__((unused)))
@@ -51,8 +54,9 @@ test_dma_map_without_dma(void **state __attribute__((unused)))
.flags = VFIO_USER_F_DMA_REGION_MAPPABLE
};
int fd;
+ size_t nr_fds = 1;
- assert_int_equal(0, handle_dma_map_or_unmap(&vfu_ctx, size, true, &fd, 1, &dma_region));
+ assert_int_equal(0, handle_dma_map_or_unmap(&vfu_ctx, size, true, &fd, &nr_fds, &dma_region));
}
static void
@@ -65,7 +69,9 @@ test_dma_map_mappable_without_fd(void **state __attribute__((unused)))
.flags = VFIO_USER_F_DMA_REGION_MAPPABLE
};
int fd;
- assert_int_equal(-EINVAL, handle_dma_map_or_unmap(&vfu_ctx, size, true, &fd, 0, &dma_region));
+ size_t nr_fds = 0;
+
+ assert_int_equal(-EINVAL, handle_dma_map_or_unmap(&vfu_ctx, size, true, &fd, &nr_fds, &dma_region));
}
static void
@@ -82,14 +88,16 @@ test_dma_map_without_fd(void **state __attribute__((unused)))
.offset = 0x8badf00d
};
int fd;
+ size_t nr_fds = 0;
patch(dma_controller_add_region);
+ will_return(__wrap_dma_controller_add_region, 0);
expect_value(__wrap_dma_controller_add_region, dma, vfu_ctx.dma);
expect_value(__wrap_dma_controller_add_region, dma_addr, r.addr);
expect_value(__wrap_dma_controller_add_region, size, r.size);
expect_value(__wrap_dma_controller_add_region, fd, -1);
expect_value(__wrap_dma_controller_add_region, offset, r.offset);
- assert_int_equal(0, handle_dma_map_or_unmap(&vfu_ctx, size, true, &fd, 0, &r));
+ assert_int_equal(0, handle_dma_map_or_unmap(&vfu_ctx, size, true, &fd, &nr_fds, &r));
}
/*
@@ -116,8 +124,11 @@ test_dma_add_regions_mixed(void **state __attribute__((unused)))
}
};
int fd = 0x8badf00d;
+ size_t nr_fds = 1;
patch(dma_controller_add_region);
+ will_return(__wrap_dma_controller_add_region, 0);
+ will_return(__wrap_dma_controller_add_region, 0);
expect_value(__wrap_dma_controller_add_region, dma, vfu_ctx.dma);
expect_value(__wrap_dma_controller_add_region, dma_addr, r[0].addr);
expect_value(__wrap_dma_controller_add_region, size, r[0].size);
@@ -129,9 +140,73 @@ test_dma_add_regions_mixed(void **state __attribute__((unused)))
expect_value(__wrap_dma_controller_add_region, fd, fd);
expect_value(__wrap_dma_controller_add_region, offset, r[1].offset);
- assert_int_equal(0, handle_dma_map_or_unmap(&vfu_ctx, sizeof r, true, &fd, 1, r));
+ assert_int_equal(0, handle_dma_map_or_unmap(&vfu_ctx, sizeof r, true, &fd, &nr_fds, r));
}
+/*
+ * Tests that handle_dma_map_or_unmap sets the correct number of file
+ * descriptors when failing halfway through.
+ */
+static void
+test_dma_add_regions_mixed_partial_failure(void **state __attribute__((unused)))
+{
+ dma_controller_t dma = { 0 };
+ vfu_ctx_t vfu_ctx = { .dma = &dma };
+ dma.vfu_ctx = &vfu_ctx;
+ struct vfio_user_dma_region r[3] = {
+ [0] = {
+ .addr = 0xdeadbeef,
+ .size = 0x1000,
+ .offset = 0
+ },
+ [1] = {
+ .addr = 0xcafebabe,
+ .size = 0x1000,
+ .offset = 0x1000,
+ .flags = VFIO_USER_F_DMA_REGION_MAPPABLE
+ },
+ [2] = {
+ .addr = 0xbabecafe,
+ .size = 0x1000,
+ .offset = 0x2000,
+ .flags = VFIO_USER_F_DMA_REGION_MAPPABLE
+ }
+ };
+ int fds[] = {0x8badf00d, 0xbad8f00d};
+ size_t nr_fds = 2;
+
+ patch(dma_controller_add_region);
+
+ /* 1st region */
+ expect_value(__wrap_dma_controller_add_region, dma, vfu_ctx.dma);
+ expect_value(__wrap_dma_controller_add_region, dma_addr, r[0].addr);
+ expect_value(__wrap_dma_controller_add_region, size, r[0].size);
+ expect_value(__wrap_dma_controller_add_region, fd, -1);
+ expect_value(__wrap_dma_controller_add_region, offset, r[0].offset);
+ will_return(__wrap_dma_controller_add_region, 0);
+
+ /* 2nd region */
+ expect_value(__wrap_dma_controller_add_region, dma, vfu_ctx.dma);
+ expect_value(__wrap_dma_controller_add_region, dma_addr, r[1].addr);
+ expect_value(__wrap_dma_controller_add_region, size, r[1].size);
+ expect_value(__wrap_dma_controller_add_region, fd, fds[0]);
+ expect_value(__wrap_dma_controller_add_region, offset, r[1].offset);
+ will_return(__wrap_dma_controller_add_region, 0);
+
+ /* 3rd region */
+ expect_value(__wrap_dma_controller_add_region, dma, vfu_ctx.dma);
+ expect_value(__wrap_dma_controller_add_region, dma_addr, r[2].addr);
+ expect_value(__wrap_dma_controller_add_region, size, r[2].size);
+ expect_value(__wrap_dma_controller_add_region, fd, fds[1]);
+ expect_value(__wrap_dma_controller_add_region, offset, r[2].offset);
+ will_return(__wrap_dma_controller_add_region, -0x1234);
+
+ assert_int_equal(-0x1234,
+ handle_dma_map_or_unmap(&vfu_ctx,
+ ARRAY_SIZE(r) * sizeof(struct vfio_user_dma_region),
+ true, fds, &nr_fds, r));
+ assert_int_equal(1, nr_fds);
+}
static void
test_dma_controller_add_region_no_fd(void **state __attribute__((unused)))
@@ -178,6 +253,81 @@ test_dma_controller_remove_region_no_fd(void **state __attribute__((unused)))
}
/*
+ * Tests that if if exec_command fails then process_request frees passed file
+ * descriptors.
+ */
+static void
+test_process_command_free_passed_fds(void **state __attribute__((unused)))
+{
+ int fds[] = {0xab, 0xcd};
+ int set_fds(const long unsigned int value,
+ const long unsigned int data __attribute__((unused)))
+ {
+ assert(value != 0);
+ memcpy((int*)value, fds, ARRAY_SIZE(fds) * sizeof(int));
+ return 1;
+ }
+ int set_nr_fds(const long unsigned int value,
+ const long unsigned int data)
+ {
+ int *nr_fds = (int*)value;
+ assert(nr_fds != NULL);
+ if ((void*)data == &get_next_command) {
+ *nr_fds = ARRAY_SIZE(fds);
+ } else if ((void*)data == &exec_command) {
+ *nr_fds = 1;
+ }
+ return 1;
+ }
+
+ vfu_ctx_t vfu_ctx = {
+ .conn_fd = 0xcafebabe,
+ .migration = (struct migration*)0x8badf00d
+ };
+
+ patch(device_is_stopped);
+ expect_value(__wrap_device_is_stopped, migr, vfu_ctx.migration);
+ will_return(__wrap_device_is_stopped, false);
+
+ patch(get_next_command);
+ expect_value(__wrap_get_next_command, vfu_ctx, &vfu_ctx);
+ expect_any(__wrap_get_next_command, hdr);
+ expect_check(__wrap_get_next_command, fds, &set_fds, &get_next_command);
+ expect_check(__wrap_get_next_command, nr_fds, &set_nr_fds, &get_next_command);
+ will_return(__wrap_get_next_command, 0x0000beef);
+
+ patch(exec_command);
+ expect_value(__wrap_exec_command, vfu_ctx, &vfu_ctx);
+ expect_any(__wrap_exec_command, hdr);
+ expect_value(__wrap_exec_command, size, 0x0000beef);
+ expect_any(__wrap_exec_command, fds);
+ expect_check(__wrap_exec_command, nr_fds, &set_nr_fds, &exec_command);
+ expect_any(__wrap_exec_command, _iovecs);
+ expect_any(__wrap_exec_command, iovecs);
+ expect_any(__wrap_exec_command, nr_iovecs);
+ expect_any(__wrap_exec_command, free_iovec_data);
+ will_return(__wrap_exec_command, -0x1234);
+
+ patch(close);
+ expect_value(__wrap_close, fd, 0xcd);
+ will_return(__wrap_close, 0);
+
+ patch(vfu_send_iovec);
+ expect_value(__wrap_vfu_send_iovec, sock, vfu_ctx.conn_fd);
+ expect_any(__wrap_vfu_send_iovec, msg_id);
+ expect_value(__wrap_vfu_send_iovec, is_reply, true);
+ expect_any(__wrap_vfu_send_iovec, cmd);
+ expect_any(__wrap_vfu_send_iovec, iovecs);
+ expect_any(__wrap_vfu_send_iovec, nr_iovecs);
+ expect_any(__wrap_vfu_send_iovec, fds);
+ expect_any(__wrap_vfu_send_iovec, count);
+ expect_any(__wrap_vfu_send_iovec, err);
+ will_return(__wrap_vfu_send_iovec, 0);
+
+ assert_int_equal(0, process_request(&vfu_ctx));
+}
+
+/*
* FIXME we shouldn't have to specify a setup function explicitly for each unit
* test, cmocka should provide that. E.g. cmocka_run_group_tests enables us to
* run a function before/after ALL unit tests have finished, we can extend it
@@ -196,8 +346,10 @@ int main(void)
cmocka_unit_test_setup(test_dma_map_mappable_without_fd, setup),
cmocka_unit_test_setup(test_dma_map_without_fd, setup),
cmocka_unit_test_setup(test_dma_add_regions_mixed, setup),
+ cmocka_unit_test_setup(test_dma_add_regions_mixed_partial_failure, setup),
cmocka_unit_test_setup(test_dma_controller_add_region_no_fd, setup),
cmocka_unit_test_setup(test_dma_controller_remove_region_no_fd, setup),
+ cmocka_unit_test_setup(test_process_command_free_passed_fds, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);