From patchwork Wed Mar 14 17:46:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Marzinski X-Patchwork-Id: 10284163 X-Patchwork-Delegate: christophe.varoqui@free.fr Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id EE21060291 for ; Thu, 15 Mar 2018 09:33:19 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EC3DB2896A for ; Thu, 15 Mar 2018 09:33:19 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E0C0928971; Thu, 15 Mar 2018 09:33:19 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 92B6028972 for ; Thu, 15 Mar 2018 09:33:18 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C4266155E0; Thu, 15 Mar 2018 09:33:17 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 9B0BD63762; Thu, 15 Mar 2018 09:33:17 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 6D4D6180BAD7; Thu, 15 Mar 2018 09:33:17 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w2EHl9kT031423 for ; Wed, 14 Mar 2018 13:47:21 -0400 Received: by smtp.corp.redhat.com (Postfix) id 565D22026E03; Wed, 14 Mar 2018 17:47:09 +0000 (UTC) Delivered-To: dm-devel@redhat.com Received: from redhat.com (octiron.msp.redhat.com [10.15.80.209]) by smtp.corp.redhat.com (Postfix) with SMTP id 162FD2026DFD; Wed, 14 Mar 2018 17:47:08 +0000 (UTC) Received: by redhat.com (sSMTP sendmail emulation); Wed, 14 Mar 2018 12:47:07 -0500 From: "Benjamin Marzinski" To: dm-devel@redhat.com Date: Wed, 14 Mar 2018 12:46:45 -0500 Message-Id: <1521049605-22050-13-git-send-email-bmarzins@redhat.com> In-Reply-To: <1521049605-22050-1-git-send-email-bmarzins@redhat.com> References: <1521049605-22050-1-git-send-email-bmarzins@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-loop: dm-devel@redhat.com X-Mailman-Approved-At: Thu, 15 Mar 2018 05:30:53 -0400 Cc: Martin Wilck , christophe.varoqui@free.fr Subject: [dm-devel] [PATCH 12/12] multipath: add unit tests for dmevents code X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Thu, 15 Mar 2018 09:33:18 +0000 (UTC) X-Virus-Scanned: ClamAV using ClamSMTP These unit tests do not get complete code coverage. Also, they don't check for memory errors. To do this through unit tests, instead of using valgrid, would require adding unit test specific compilation defines to the code, and compiling a seperate unit-test version. Signed-off-by: Benjamin Marzinski Reviewed-by: Martin Wilck --- tests/Makefile | 9 +- tests/dmevents.c | 847 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 853 insertions(+), 3 deletions(-) create mode 100644 tests/dmevents.c diff --git a/tests/Makefile b/tests/Makefile index 3450b14..1f36411 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -3,11 +3,16 @@ include ../Makefile.inc CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) LIBDEPS += -L$(multipathdir) -lmultipath -lcmocka -TESTS := uevent parser util +TESTS := uevent parser util dmevents .SILENT: $(TESTS:%=%.o) .PRECIOUS: $(TESTS:%=%-test) +all: $(TESTS:%=%.out) + +dmevents-test: dmevents.o ../multipathd/dmevents.c globals.c $(multipathdir)/libmultipath.so + @$(CC) -o $@ $< $(LDFLAGS) $(LIBDEPS) -lpthread -ldevmapper -lurcu -Wl,--wrap=open -Wl,--wrap=close -Wl,--wrap=dm_is_mpath -Wl,--wrap=dm_geteventnr -Wl,--wrap=ioctl -Wl,--wrap=libmp_dm_task_create -Wl,--wrap=dm_task_no_open_count -Wl,--wrap=dm_task_run -Wl,--wrap=dm_task_get_names -Wl,--wrap=dm_task_destroy -Wl,--wrap=poll -Wl,--wrap=remove_map_by_alias -Wl,--wrap=update_multipath + %-test: %.o globals.c $(multipathdir)/libmultipath.so @$(CC) -o $@ $< $(LDFLAGS) $(LIBDEPS) @@ -15,8 +20,6 @@ TESTS := uevent parser util @echo == running $< == @LD_LIBRARY_PATH=$(multipathdir):$(mpathcmddir) ./$< >$@ -all: $(TESTS:%=%.out) - clean: dep_clean rm -f $(TESTS:%=%-test) $(TESTS:%=%.out) $(TESTS:%=%.o) diff --git a/tests/dmevents.c b/tests/dmevents.c new file mode 100644 index 0000000..4442fc2 --- /dev/null +++ b/tests/dmevents.c @@ -0,0 +1,847 @@ +/* + * Copyright (c) 2018 Benjamin Marzinski, Redhat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "structs.h" +#include "structs_vec.h" + +#include "globals.c" +/* I have to do this to get at the static variables */ +#include "../multipathd/dmevents.c" + +struct dm_device { + char name[WWID_SIZE]; + int is_mpath; + uint32_t evt_nr; + uint32_t update_nr; +}; + +struct test_data { + struct vectors vecs; + vector dm_devices; + struct dm_names *names; +}; + +struct test_data data; + +int add_dm_device_event(char *name, int is_mpath, uint32_t evt_nr) +{ + struct dm_device *dev; + int i; + + vector_foreach_slot(data.dm_devices, dev, i) { + if (strcmp(name, dev->name) == 0) { + dev->evt_nr = evt_nr; + return 0; + } + } + dev = (struct dm_device *)malloc(sizeof(struct dm_device)); + if (!dev){ + condlog(0, "Testing error mallocing dm_device"); + return -1; + } + strncpy(dev->name, name, WWID_SIZE); + dev->name[WWID_SIZE - 1] = 0; + dev->is_mpath = is_mpath; + dev->evt_nr = evt_nr; + if (!vector_alloc_slot(data.dm_devices)) { + condlog(0, "Testing error setting dm_devices slot"); + free(dev); + return -1; + } + vector_set_slot(data.dm_devices, dev); + return 0; +} + +struct dm_device *find_dm_device(const char *name) +{ + struct dm_device *dev; + int i; + + vector_foreach_slot(data.dm_devices, dev, i) + if (strcmp(name, dev->name) == 0) + return dev; + return NULL; +} + +int remove_dm_device_event(const char *name) +{ + struct dm_device *dev; + int i; + + vector_foreach_slot(data.dm_devices, dev, i) { + if (strcmp(name, dev->name) == 0) { + vector_del_slot(data.dm_devices, i); + free(dev); + return 0; + } + } + return -1; +} + +void remove_all_dm_device_events(void) +{ + struct dm_device *dev; + int i; + + vector_foreach_slot(data.dm_devices, dev, i) + free(dev); + vector_reset(data.dm_devices); +} + +static inline size_t align_val(size_t val) +{ + return (val + 7) & ~7; +} +static inline void *align_ptr(void *ptr) +{ + return (void *)align_val((size_t)ptr); +} + +/* copied off of list_devices in dm-ioctl.c */ +struct dm_names *build_dm_names(void) +{ + struct dm_names *names, *np, *old_np = NULL; + uint32_t *event_nr; + struct dm_device *dev; + int i, size = 0; + + if (VECTOR_SIZE(data.dm_devices) == 0) { + names = (struct dm_names *)malloc(sizeof(struct dm_names)); + if (!names) { + condlog(0, "Testing error allocating empty dm_names"); + return NULL; + } + names->dev = 0; + names->next = 0; + return names; + } + vector_foreach_slot(data.dm_devices, dev, i) { + size += align_val(offsetof(struct dm_names, name) + + strlen(dev->name) + 1); + size += align_val(sizeof(uint32_t)); + } + names = (struct dm_names *)malloc(size); + if (!names) { + condlog(0, "Testing error allocating dm_names"); + return NULL; + } + np = names; + vector_foreach_slot(data.dm_devices, dev, i) { + if (old_np) + old_np->next = (uint32_t) ((uintptr_t) np - + (uintptr_t) old_np); + np->dev = 1; + np->next = 0; + strcpy(np->name, dev->name); + + old_np = np; + event_nr = align_ptr(np->name + strlen(dev->name) + 1); + *event_nr = dev->evt_nr; + np = align_ptr(event_nr + 1); + } + assert_int_equal((char *)np - (char *)names, size); + return names; +} + +static int setup(void **state) +{ + if (dmevent_poll_supported()) { + data.dm_devices = vector_alloc(); + *state = &data; + } else + *state = NULL; + return 0; +} + +static int teardown(void **state) +{ + struct dm_device *dev; + int i; + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + return 0; + vector_foreach_slot(datap->dm_devices, dev, i) + free(dev); + vector_free(datap->dm_devices); + datap = NULL; + return 0; +} + +int __wrap_open(const char *pathname, int flags) +{ + assert_ptr_equal(pathname, "/dev/mapper/control"); + assert_int_equal(flags, O_RDWR); + return mock_type(int); +} + +int __wrap_close(int fd) +{ + assert_int_equal(fd, waiter->fd); + return 0; +} + +int __wrap_dm_is_mpath(const char *name) +{ + struct dm_device *dev; + int i; + + vector_foreach_slot(data.dm_devices, dev, i) + if (strcmp(name, dev->name) == 0) + return dev->is_mpath; + return 0; +} + +int __wrap_dm_geteventnr(const char *name) +{ + struct dm_device *dev; + int fail = mock_type(int); + + if (fail) + return -1; + dev = find_dm_device(name); + if (dev) { + /* simulate updating device state after adding it */ + dev->update_nr = dev->evt_nr; + return dev->evt_nr; + } + return -1; +} + +int __wrap_ioctl(int fd, unsigned long request, void *argp) +{ + assert_int_equal(fd, waiter->fd); + assert_int_equal(request, DM_DEV_ARM_POLL); + return mock_type(int); +} + +struct dm_task *__wrap_libmp_dm_task_create(int task) +{ + assert_int_equal(task, DM_DEVICE_LIST); + return mock_type(struct dm_task *); +} + +int __wrap_dm_task_no_open_count(struct dm_task *dmt) +{ + assert_ptr_equal((struct test_data *)dmt, &data); + return mock_type(int); +} + +int __wrap_dm_task_run(struct dm_task *dmt) +{ + assert_ptr_equal((struct test_data *)dmt, &data); + return mock_type(int); +} + +struct dm_names * __wrap_dm_task_get_names(struct dm_task *dmt) +{ + int good = mock_type(int); + assert_ptr_equal((struct test_data *)dmt, &data); + + if (data.names) { + condlog(0, "Testing error. data.names already allocated"); + return NULL; + } + if (!good) + return NULL; + data.names = build_dm_names(); + return data.names; +} + +void __wrap_dm_task_destroy(struct dm_task *dmt) +{ + assert_ptr_equal((struct test_data *)dmt, &data); + + if (data.names) { + free(data.names); + data.names = NULL; + } +} + +int __wrap_poll(struct pollfd *fds, nfds_t nfds, int timeout) +{ + assert_int_equal(nfds, 1); + assert_int_equal(timeout, -1); + assert_int_equal(fds->fd, waiter->fd); + assert_int_equal(fds->events, POLLIN); + return mock_type(int); +} + +void __wrap_remove_map_by_alias(const char *alias, struct vectors * vecs, + int purge_vec) +{ + check_expected(alias); + assert_ptr_equal(vecs, waiter->vecs); + assert_int_equal(purge_vec, 1); +} + +int __wrap_update_multipath(struct vectors *vecs, char *mapname, int reset) +{ + int fail; + + check_expected(mapname); + assert_ptr_equal(vecs, waiter->vecs); + assert_int_equal(reset, 1); + fail = mock_type(int); + if (fail) { + assert_int_equal(remove_dm_device_event(mapname), 0); + return fail; + } else { + struct dm_device *dev; + int i; + + vector_foreach_slot(data.dm_devices, dev, i) { + if (strcmp(mapname, dev->name) == 0) { + dev->update_nr = dev->evt_nr; + return 0; + } + } + fail(); + } + return fail; +} + +struct dev_event *find_dmevents(const char *name) +{ + struct dev_event *dev_evt; + int i; + + vector_foreach_slot(waiter->events, dev_evt, i) + if (!strcmp(dev_evt->name, name)) + return dev_evt; + return NULL; +} + +static void test_init_waiter_bad0(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + assert_int_equal(init_dmevent_waiter(NULL), -1); +} + +static void test_init_waiter_bad1(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + will_return(__wrap_open, -1); + assert_int_equal(init_dmevent_waiter(&datap->vecs), -1); + assert_ptr_equal(waiter, NULL); +} + +static void test_init_waiter_good0(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + will_return(__wrap_open, 2); + assert_int_equal(init_dmevent_waiter(&datap->vecs), 0); + assert_ptr_not_equal(waiter, NULL); +} + +static void test_watch_dmevents_bad0(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + assert_int_equal(watch_dmevents("foo"), -1); + assert_ptr_equal(find_dmevents("foo"), NULL); +} + +static void test_watch_dmevents_bad1(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + assert_int_equal(add_dm_device_event("foo", 0, 5), 0); + assert_int_equal(watch_dmevents("foo"), -1); + assert_ptr_equal(find_dmevents("foo"), NULL); +} + +static void test_watch_dmevents_bad2(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + remove_all_dm_device_events(); + assert_int_equal(add_dm_device_event("foo", 1, 5), 0); + will_return(__wrap_dm_geteventnr, -1); + assert_int_equal(watch_dmevents("foo"), -1); + assert_ptr_equal(find_dmevents("foo"), NULL); +} +static void test_watch_dmevents_good0(void **state) +{ + struct dev_event *dev_evt; + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + remove_all_dm_device_events(); + assert_int_equal(add_dm_device_event("foo", 1, 5), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("foo"), 0); + dev_evt = find_dmevents("foo"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 5); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + assert_int_equal(VECTOR_SIZE(waiter->events), 1); + unwatch_dmevents("foo"); + assert_int_equal(VECTOR_SIZE(waiter->events), 0); + assert_ptr_equal(find_dmevents("foo"), NULL); +} + +static void test_watch_dmevents_good1(void **state) +{ + struct dev_event *dev_evt; + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + remove_all_dm_device_events(); + assert_int_equal(add_dm_device_event("foo", 1, 5), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("foo"), 0); + dev_evt = find_dmevents("foo"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 5); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + assert_int_equal(add_dm_device_event("foo", 1, 6), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("foo"), 0); + dev_evt = find_dmevents("foo"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 6); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + assert_int_equal(VECTOR_SIZE(waiter->events), 1); + unwatch_dmevents("foo"); + assert_int_equal(VECTOR_SIZE(waiter->events), 0); + assert_ptr_equal(find_dmevents("foo"), NULL); +} + +static void test_watch_dmevents_good2(void **state) +{ + struct dev_event *dev_evt; + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + unwatch_all_dmevents(); + remove_all_dm_device_events(); + assert_int_equal(add_dm_device_event("foo", 1, 5), 0); + assert_int_equal(add_dm_device_event("bar", 1, 7), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("foo"), 0); + dev_evt = find_dmevents("foo"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 5); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + assert_ptr_equal(find_dmevents("bar"), NULL); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("bar"), 0); + dev_evt = find_dmevents("foo"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 5); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + dev_evt = find_dmevents("bar"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 7); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + assert_int_equal(VECTOR_SIZE(waiter->events), 2); + unwatch_all_dmevents(); + assert_int_equal(VECTOR_SIZE(waiter->events), 0); + assert_ptr_equal(find_dmevents("foo"), NULL); + assert_ptr_equal(find_dmevents("bar"), NULL); +} + +static void test_get_events_bad0(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + unwatch_all_dmevents(); + remove_all_dm_device_events(); + + will_return(__wrap_libmp_dm_task_create, NULL); + assert_int_equal(dm_get_events(), -1); +} + +static void test_get_events_bad1(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + will_return(__wrap_libmp_dm_task_create, &data); + will_return(__wrap_dm_task_no_open_count, 1); + will_return(__wrap_dm_task_run, 0); + assert_int_equal(dm_get_events(), -1); +} + +static void test_get_events_bad2(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + will_return(__wrap_libmp_dm_task_create, &data); + will_return(__wrap_dm_task_no_open_count, 1); + will_return(__wrap_dm_task_run, 1); + will_return(__wrap_dm_task_get_names, 0); + assert_int_equal(dm_get_events(), -1); +} + +static void test_get_events_good0(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + assert_int_equal(add_dm_device_event("foo", 1, 5), 0); + will_return(__wrap_libmp_dm_task_create, &data); + will_return(__wrap_dm_task_no_open_count, 1); + will_return(__wrap_dm_task_run, 1); + will_return(__wrap_dm_task_get_names, 1); + assert_int_equal(dm_get_events(), 0); + assert_ptr_equal(find_dmevents("foo"), NULL); + assert_int_equal(VECTOR_SIZE(waiter->events), 0); +} + +static void test_get_events_good1(void **state) +{ + struct dev_event *dev_evt; + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + remove_all_dm_device_events(); + assert_int_equal(add_dm_device_event("foo", 1, 5), 0); + assert_int_equal(add_dm_device_event("bar", 1, 7), 0); + assert_int_equal(add_dm_device_event("baz", 1, 12), 0); + assert_int_equal(add_dm_device_event("qux", 0, 4), 0); + assert_int_equal(add_dm_device_event("xyzzy", 1, 8), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("foo"), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("bar"), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("xyzzy"), 0); + assert_int_equal(add_dm_device_event("foo", 1, 6), 0); + assert_int_equal(remove_dm_device_event("xyzzy"), 0); + will_return(__wrap_libmp_dm_task_create, &data); + will_return(__wrap_dm_task_no_open_count, 1); + will_return(__wrap_dm_task_run, 1); + will_return(__wrap_dm_task_get_names, 1); + assert_int_equal(dm_get_events(), 0); + dev_evt = find_dmevents("foo"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 6); + assert_int_equal(dev_evt->action, EVENT_UPDATE); + dev_evt = find_dmevents("bar"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 7); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + dev_evt = find_dmevents("xyzzy"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 8); + assert_int_equal(dev_evt->action, EVENT_REMOVE); + assert_ptr_equal(find_dmevents("baz"), NULL); + assert_ptr_equal(find_dmevents("qux"), NULL); + assert_int_equal(VECTOR_SIZE(waiter->events), 3); +} + +static void test_dmevent_loop_bad0(void **state) +{ + struct dm_device *dev; + struct dev_event *dev_evt; + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + remove_all_dm_device_events(); + unwatch_all_dmevents(); + assert_int_equal(add_dm_device_event("foo", 1, 5), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("foo"), 0); + assert_int_equal(add_dm_device_event("foo", 1, 6), 0); + will_return(__wrap_poll, 0); + assert_int_equal(dmevent_loop(), 1); + dev_evt = find_dmevents("foo"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 5); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + dev = find_dm_device("foo"); + assert_ptr_not_equal(dev, NULL); + assert_int_equal(dev->evt_nr, 6); + assert_int_equal(dev->update_nr, 5); +} + +static void test_dmevent_loop_bad1(void **state) +{ + struct dm_device *dev; + struct dev_event *dev_evt; + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + will_return(__wrap_poll, 1); + will_return(__wrap_ioctl, -1); + assert_int_equal(dmevent_loop(), 1); + dev_evt = find_dmevents("foo"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 5); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + dev = find_dm_device("foo"); + assert_ptr_not_equal(dev, NULL); + assert_int_equal(dev->evt_nr, 6); + assert_int_equal(dev->update_nr, 5); +} + +static void test_dmevent_loop_bad2(void **state) +{ + struct dm_device *dev; + struct dev_event *dev_evt; + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + will_return(__wrap_poll, 1); + will_return(__wrap_ioctl, 0); + will_return(__wrap_libmp_dm_task_create, NULL); + assert_int_equal(dmevent_loop(), 1); + dev_evt = find_dmevents("foo"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 5); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + dev = find_dm_device("foo"); + assert_ptr_not_equal(dev, NULL); + assert_int_equal(dev->evt_nr, 6); + assert_int_equal(dev->update_nr, 5); +} + +static void test_dmevent_loop_good0(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + remove_all_dm_device_events(); + unwatch_all_dmevents(); + will_return(__wrap_poll, 1); + will_return(__wrap_ioctl, 0); + will_return(__wrap_libmp_dm_task_create, &data); + will_return(__wrap_dm_task_no_open_count, 1); + will_return(__wrap_dm_task_run, 1); + will_return(__wrap_dm_task_get_names, 1); + assert_int_equal(dmevent_loop(), 1); +} + +static void test_dmevent_loop_good1(void **state) +{ + struct dm_device *dev; + struct dev_event *dev_evt; + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + remove_all_dm_device_events(); + unwatch_all_dmevents(); + assert_int_equal(add_dm_device_event("foo", 1, 5), 0); + assert_int_equal(add_dm_device_event("bar", 1, 7), 0); + assert_int_equal(add_dm_device_event("baz", 1, 12), 0); + assert_int_equal(add_dm_device_event("xyzzy", 1, 8), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("foo"), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("bar"), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("xyzzy"), 0); + assert_int_equal(add_dm_device_event("foo", 1, 6), 0); + assert_int_equal(remove_dm_device_event("xyzzy"), 0); + will_return(__wrap_poll, 1); + will_return(__wrap_ioctl, 0); + will_return(__wrap_libmp_dm_task_create, &data); + will_return(__wrap_dm_task_no_open_count, 1); + will_return(__wrap_dm_task_run, 1); + will_return(__wrap_dm_task_get_names, 1); + expect_string(__wrap_update_multipath, mapname, "foo"); + will_return(__wrap_update_multipath, 0); + expect_string(__wrap_remove_map_by_alias, alias, "xyzzy"); + assert_int_equal(dmevent_loop(), 1); + assert_int_equal(VECTOR_SIZE(waiter->events), 2); + assert_int_equal(VECTOR_SIZE(data.dm_devices), 3); + dev_evt = find_dmevents("foo"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 6); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + dev = find_dm_device("foo"); + assert_ptr_not_equal(dev, NULL); + assert_int_equal(dev->evt_nr, 6); + assert_int_equal(dev->update_nr, 6); + dev_evt = find_dmevents("bar"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 7); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + dev = find_dm_device("bar"); + assert_ptr_not_equal(dev, NULL); + assert_int_equal(dev->evt_nr, 7); + assert_int_equal(dev->update_nr, 7); + assert_ptr_equal(find_dmevents("xyzzy"), NULL); + assert_ptr_equal(find_dm_device("xyzzy"), NULL); +} + +static void test_dmevent_loop_good2(void **state) +{ + struct dm_device *dev; + struct dev_event *dev_evt; + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + assert_int_equal(add_dm_device_event("bar", 1, 9), 0); + will_return(__wrap_dm_geteventnr, 0); + assert_int_equal(watch_dmevents("baz"), 0); + assert_int_equal(add_dm_device_event("baz", 1, 14), 0); + will_return(__wrap_poll, 1); + will_return(__wrap_ioctl, 0); + will_return(__wrap_libmp_dm_task_create, &data); + will_return(__wrap_dm_task_no_open_count, 1); + will_return(__wrap_dm_task_run, 1); + will_return(__wrap_dm_task_get_names, 1); + expect_string(__wrap_update_multipath, mapname, "bar"); + will_return(__wrap_update_multipath, 0); + expect_string(__wrap_update_multipath, mapname, "baz"); + will_return(__wrap_update_multipath, 1); + assert_int_equal(dmevent_loop(), 1); + assert_int_equal(VECTOR_SIZE(waiter->events), 2); + assert_int_equal(VECTOR_SIZE(data.dm_devices), 2); + dev_evt = find_dmevents("foo"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 6); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + dev = find_dm_device("foo"); + assert_ptr_not_equal(dev, NULL); + assert_int_equal(dev->evt_nr, 6); + assert_int_equal(dev->update_nr, 6); + dev_evt = find_dmevents("bar"); + assert_ptr_not_equal(dev_evt, NULL); + assert_int_equal(dev_evt->evt_nr, 9); + assert_int_equal(dev_evt->action, EVENT_NOTHING); + dev = find_dm_device("bar"); + assert_ptr_not_equal(dev, NULL); + assert_int_equal(dev->evt_nr, 9); + assert_int_equal(dev->update_nr, 9); + assert_ptr_equal(find_dmevents("baz"), NULL); + assert_ptr_equal(find_dm_device("baz"), NULL); +} + +static void test_dmevent_loop_good3(void **state) +{ + struct dm_device *dev; + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + + assert_int_equal(remove_dm_device_event("foo"), 0); + unwatch_dmevents("bar"); + will_return(__wrap_poll, 1); + will_return(__wrap_ioctl, 0); + will_return(__wrap_libmp_dm_task_create, &data); + will_return(__wrap_dm_task_no_open_count, 1); + will_return(__wrap_dm_task_run, 1); + will_return(__wrap_dm_task_get_names, 1); + expect_string(__wrap_remove_map_by_alias, alias, "foo"); + assert_int_equal(dmevent_loop(), 1); + assert_int_equal(VECTOR_SIZE(waiter->events), 0); + assert_int_equal(VECTOR_SIZE(data.dm_devices), 1); + dev = find_dm_device("bar"); + assert_ptr_not_equal(dev, NULL); + assert_int_equal(dev->evt_nr, 9); + assert_int_equal(dev->update_nr, 9); + assert_ptr_equal(find_dmevents("foo"), NULL); + assert_ptr_equal(find_dmevents("bar"), NULL); + assert_ptr_equal(find_dm_device("foo"), NULL); +} + +static void test_arm_poll(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + will_return(__wrap_ioctl, 0); + assert_int_equal(arm_dm_event_poll(waiter->fd), 0); +} + +static void test_cleanup_waiter(void **state) +{ + struct test_data *datap = (struct test_data *)(*state); + if (datap == NULL) + skip(); + cleanup_dmevent_waiter(); + assert_ptr_equal(waiter, NULL); +} + +int test_dmevents(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_init_waiter_bad0), + cmocka_unit_test(test_init_waiter_bad1), + cmocka_unit_test(test_init_waiter_good0), + cmocka_unit_test(test_watch_dmevents_bad0), + cmocka_unit_test(test_watch_dmevents_bad1), + cmocka_unit_test(test_watch_dmevents_bad2), + cmocka_unit_test(test_watch_dmevents_good0), + cmocka_unit_test(test_watch_dmevents_good1), + cmocka_unit_test(test_watch_dmevents_good2), + cmocka_unit_test(test_get_events_bad0), + cmocka_unit_test(test_get_events_bad1), + cmocka_unit_test(test_get_events_bad2), + cmocka_unit_test(test_get_events_good0), + cmocka_unit_test(test_get_events_good1), + cmocka_unit_test(test_arm_poll), + cmocka_unit_test(test_dmevent_loop_bad0), + cmocka_unit_test(test_dmevent_loop_bad1), + cmocka_unit_test(test_dmevent_loop_bad2), + cmocka_unit_test(test_dmevent_loop_good0), + cmocka_unit_test(test_dmevent_loop_good1), + cmocka_unit_test(test_dmevent_loop_good2), + cmocka_unit_test(test_dmevent_loop_good3), + cmocka_unit_test(test_cleanup_waiter), + }; + return cmocka_run_group_tests(tests, setup, teardown); +} + +int main(void) +{ + int ret = 0; + + ret += test_dmevents(); + return ret; +}