From 47a6fdbb8b3e459ba4f7815269bae0abf95d29a6 Mon Sep 17 00:00:00 2001 From: Thanos Makatos Date: Wed, 17 Feb 2021 13:15:35 +0000 Subject: add unit tests for handle dirty pages w/o DMA (#348) Signed-off-by: Thanos Makatos Reviewed-by: Swapnil Ingle --- lib/libvfio-user.c | 4 +++- test/CMakeLists.txt | 1 + test/mocks.c | 28 +++++++++++++++++++++++++++- test/mocks.h | 6 ++++++ test/unit-tests.c | 41 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c index 053a2d4..ab6f4a3 100644 --- a/lib/libvfio-user.c +++ b/lib/libvfio-user.c @@ -621,7 +621,7 @@ out: return ret; } -static int +int handle_dirty_pages(vfu_ctx_t *vfu_ctx, uint32_t size, struct iovec **iovecs, size_t *nr_iovecs, struct vfio_iommu_type1_dirty_bitmap *dirty_bitmap) @@ -654,6 +654,8 @@ handle_dirty_pages(vfu_ctx_t *vfu_ctx, uint32_t size, return ret; } +UNIT_TEST_SYMBOL(handle_dirty_pages); +#define handle_dirty_pages __wrap_handle_dirty_pages /* * FIXME return value is messed up, sometimes we return -1 and set errno while diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a4f49ad..11e243d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -55,6 +55,7 @@ target_link_libraries(unit-tests PUBLIC "-Wl,--wrap=free") target_link_libraries(unit-tests PUBLIC "-Wl,--wrap=process_request") target_link_libraries(unit-tests PUBLIC "-Wl,--wrap=bind") target_link_libraries(unit-tests PUBLIC "-Wl,--wrap=listen") +target_link_libraries(unit-tests PUBLIC "-Wl,--wrap=handle_dirty_pages") enable_testing() add_test(NAME unit-tests COMMAND unit-tests) diff --git a/test/mocks.c b/test/mocks.c index 303a6c2..80545e6 100644 --- a/test/mocks.c +++ b/test/mocks.c @@ -88,6 +88,9 @@ __wrap__dma_controller_do_remove_region(dma_controller_t *dma, bool __wrap_device_is_stopped(struct migration *migr) { + if (!is_patched(device_is_stopped)) { + return __real_device_is_stopped(migr); + } check_expected(migr); return mock(); } @@ -109,6 +112,11 @@ __wrap_exec_command(vfu_ctx_t *vfu_ctx, struct vfio_user_header *hdr, int *nr_fds_out, struct iovec *_iovecs, struct iovec **iovecs, size_t *nr_iovecs, bool *free_iovec_data) { + if (!is_patched(exec_command)) { + return __real_exec_command(vfu_ctx, hdr, size, fds, nr_fds, fds_out, + nr_fds_out, _iovecs, iovecs, nr_iovecs, + free_iovec_data); + } check_expected(vfu_ctx); check_expected(hdr); check_expected(size); @@ -187,6 +195,23 @@ int __wrap_listen(int sockfd __attribute__((unused)), return 0; } +int +__wrap_handle_dirty_pages(vfu_ctx_t *vfu_ctx, uint32_t size, + struct iovec **iovecs, size_t *nr_iovecs, + struct vfio_iommu_type1_dirty_bitmap *dirty_bitmap) +{ + if (!is_patched(handle_dirty_pages)) { + return __real_handle_dirty_pages(vfu_ctx, size, iovecs, nr_iovecs, + dirty_bitmap); + } + check_expected(vfu_ctx); + check_expected(size); + check_expected(iovecs); + check_expected(nr_iovecs); + check_expected(dirty_bitmap); + return mock(); +} + /* FIXME should be something faster than unsorted array, look at tsearch(3). */ static struct function funcs[] = { {.addr = &__wrap_dma_controller_add_region}, @@ -200,7 +225,8 @@ static struct function funcs[] = { {.addr = &__wrap_free}, {.addr = &__wrap_process_request}, {.addr = &__wrap_bind}, - {.addr = &__wrap_listen} + {.addr = &__wrap_listen}, + {.addr = &__wrap_handle_dirty_pages}, }; static struct function* diff --git a/test/mocks.h b/test/mocks.h index 97a23b7..67a67b5 100644 --- a/test/mocks.h +++ b/test/mocks.h @@ -29,6 +29,7 @@ */ #include +#include "private.h" void unpatch_all(void); @@ -36,4 +37,9 @@ void patch(void *fn); bool is_patched(void *fn); +int +handle_dirty_pages(vfu_ctx_t *vfu_ctx, uint32_t size, + struct iovec **iovecs, size_t *nr_iovecs, + struct vfio_iommu_type1_dirty_bitmap *dirty_bitmap); + /* ex: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/test/unit-tests.c b/test/unit-tests.c index eda8c49..4ab51e4 100644 --- a/test/unit-tests.c +++ b/test/unit-tests.c @@ -46,6 +46,7 @@ #include "pci.h" #include "private.h" #include "migration.h" +#include "mocks.h" #include "tran_sock.h" static void @@ -1390,6 +1391,45 @@ test_setup_migration_callbacks(void **state) /* FIXME can't validate p->v->migration because it's a private strcut, need to move it out of lib/migration.c */ } +static void +test_dirty_pages_without_dma(UNUSED void **state) +{ + vfu_ctx_t vfu_ctx = { .migration = NULL }; + struct vfio_user_header hdr = { + .cmd = VFIO_USER_DIRTY_PAGES, + .flags = { + .type = VFIO_USER_F_TYPE_COMMAND + }, + .msg_size = sizeof hdr + }; + size_t size = sizeof hdr; + int fds = 0; + struct iovec _iovecs = { 0 }; + struct iovec *iovecs = NULL; + size_t nr_iovecs = 0; + bool free_iovec_data = false; + int r; + + patch(handle_dirty_pages); + + /* XXX w/o DMA controller */ + r = exec_command(&vfu_ctx, &hdr, size, &fds, 0, NULL, NULL, + &_iovecs, &iovecs, &nr_iovecs, &free_iovec_data); + assert_int_equal(0, r); + + /* XXX w/ DMA controller */ + vfu_ctx.dma = (void*)0xdeadbeef; + expect_value(__wrap_handle_dirty_pages, vfu_ctx, &vfu_ctx); + expect_value(__wrap_handle_dirty_pages, size, 0); + expect_value(__wrap_handle_dirty_pages, iovecs, &iovecs); + expect_value(__wrap_handle_dirty_pages, nr_iovecs, &nr_iovecs); + expect_value(__wrap_handle_dirty_pages, dirty_bitmap, NULL); + will_return(__wrap_handle_dirty_pages, 0xabcd); + r = exec_command(&vfu_ctx, &hdr, size, &fds, 0, NULL, NULL, + &_iovecs, &iovecs, &nr_iovecs, &free_iovec_data); + assert_int_equal(0xabcd, r); +} + int main(void) { const struct CMUnitTest tests[] = { @@ -1440,6 +1480,7 @@ int main(void) cmocka_unit_test_setup_teardown(test_setup_migration_callbacks, setup_test_setup_migration_region, teardown_test_setup_migration_region), + cmocka_unit_test_setup(test_dirty_pages_without_dma, setup), }; return cmocka_run_group_tests(tests, NULL, NULL); -- cgit v1.1