236c514b74eb9a6ddfef4e1f808d9c678676b5b7
[multipath-tools/.git] / tests / directio.c
1 /*
2  * Copyright (c) 2018 Benjamin Marzinski, Redhat
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  *
17  */
18
19 #define _GNU_SOURCE
20 #include <stdint.h>
21 #include <stdbool.h>
22 #include <stdarg.h>
23 #include <stddef.h>
24 #include <setjmp.h>
25 #include <stdlib.h>
26 #define UNIT_TESTING /* enable memory testing in directio.c */
27 #include <cmocka.h>
28 #include "globals.c"
29 #include "../libmultipath/checkers/directio.c"
30
31 int test_fd = 111;
32 int ioctx_count = 0;
33 struct io_event mock_events[AIO_GROUP_SIZE]; /* same as the checker max */
34 int ev_off = 0;
35 struct timespec zero_timeout = {0};
36 struct timespec full_timeout = { .tv_sec = -1 };
37
38 int __real_ioctl(int fd, unsigned long request, void *argp);
39
40 int __wrap_ioctl(int fd, unsigned long request, void *argp)
41 {
42 #ifdef DIO_TEST_DEV
43         mock_type(int);
44         return __real_ioctl(fd, request, argp);
45 #else
46         int *blocksize = (int *)argp;
47
48         assert_int_equal(fd, test_fd);
49         assert_int_equal(request, BLKBSZGET);
50         assert_non_null(blocksize);
51         *blocksize = mock_type(int);
52         return 0;
53 #endif
54 }
55
56 int __real_fcntl(int fd, int cmd, long arg);
57
58 int __wrap_fcntl(int fd, int cmd, long arg)
59 {
60 #ifdef DIO_TEST_DEV
61         return __real_fcntl(fd, cmd, arg);
62 #else
63         assert_int_equal(fd, test_fd);
64         assert_int_equal(cmd, F_GETFL);
65         return O_DIRECT;
66 #endif
67 }
68
69 int __real___fxstat(int ver, int fd, struct stat *statbuf);
70
71 int __wrap___fxstat(int ver, int fd, struct stat *statbuf)
72 {
73 #ifdef DIO_TEST_DEV
74         return __real___fxstat(ver, fd, statbuf);
75 #else
76         assert_int_equal(fd, test_fd);
77         assert_non_null(statbuf);
78         memset(statbuf, 0, sizeof(struct stat));
79         return 0;
80 #endif
81 }
82
83 int __real_io_setup(int maxevents, io_context_t *ctxp);
84
85 int __wrap_io_setup(int maxevents, io_context_t *ctxp)
86 {
87         ioctx_count++;
88 #ifdef DIO_TEST_DEV
89         int ret = mock_type(int);
90         assert_int_equal(ret, __real_io_setup(maxevents, ctxp));
91         return ret;
92 #else
93         return mock_type(int);
94 #endif
95 }
96
97 int __real_io_destroy(io_context_t ctx);
98
99 int __wrap_io_destroy(io_context_t ctx)
100 {
101         ioctx_count--;
102 #ifdef DIO_TEST_DEV
103         int ret = mock_type(int);
104         assert_int_equal(ret, __real_io_destroy(ctx));
105         return ret;
106 #else
107         return mock_type(int);
108 #endif
109 }
110
111 int __real_io_submit(io_context_t ctx, long nr, struct iocb *ios[]);
112
113 int __wrap_io_submit(io_context_t ctx, long nr, struct iocb *ios[])
114 {
115 #ifdef DIO_TEST_DEV
116         struct timespec dev_delay = { .tv_nsec = 100000 };
117         int ret = mock_type(int);
118         assert_int_equal(ret, __real_io_submit(ctx, nr, ios));
119         nanosleep(&dev_delay, NULL);
120         return ret;
121 #else
122         return mock_type(int);
123 #endif
124 }
125
126 int __real_io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt);
127
128 int __wrap_io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt)
129 {
130 #ifdef DIO_TEST_DEV
131         mock_type(int);
132         return __real_io_cancel(ctx, iocb, evt);
133 #else
134         return mock_type(int);
135 #endif
136 }
137
138 int __real_io_getevents(io_context_t ctx, long min_nr, long nr,
139                         struct io_event *events, struct timespec *timeout);
140
141 int __wrap_io_getevents(io_context_t ctx, long min_nr, long nr,
142                         struct io_event *events, struct timespec *timeout)
143 {
144         int nr_evs;
145 #ifndef DIO_TEST_DEV
146         struct timespec *sleep_tmo;
147         int i;
148         struct io_event *evs;
149 #endif
150
151         assert_non_null(timeout);
152         nr_evs = mock_type(int);
153         assert_true(nr_evs <= nr);
154         if (!nr_evs)
155                 return 0;
156 #ifdef DIO_TEST_DEV
157         mock_ptr_type(struct timespec *);
158         mock_ptr_type(struct io_event *);
159         assert_int_equal(nr_evs, __real_io_getevents(ctx, min_nr, nr_evs,
160                                                      events, timeout));
161 #else
162         sleep_tmo = mock_ptr_type(struct timespec *);
163         if (sleep_tmo) {
164                 if (sleep_tmo->tv_sec < 0)
165                         nanosleep(timeout, NULL);
166                 else
167                         nanosleep(sleep_tmo, NULL);
168         }
169         if (nr_evs < 0) {
170                 errno = -nr_evs;
171                 return -1;
172         }
173         evs = mock_ptr_type(struct io_event *);
174         for (i = 0; i < nr_evs; i++)
175                 events[i] = evs[i];
176 #endif
177         ev_off -= nr_evs;
178         return nr_evs;
179 }
180
181 static void return_io_getevents_none(void)
182 {
183         will_return(__wrap_io_getevents, 0);
184 }
185
186 static void return_io_getevents_nr(struct timespec *ts, int nr,
187                                    struct async_req **reqs, int *res)
188 {
189         int i, off = 0;
190
191         for(i = 0; i < nr; i++) {
192                 mock_events[i + ev_off].obj = &reqs[i]->io;
193                 if (res[i] == 0)
194                         mock_events[i + ev_off].res = reqs[i]->blksize;
195         }
196         while (nr > 0) {
197                 will_return(__wrap_io_getevents, (nr > 128)? 128 : nr);
198                 will_return(__wrap_io_getevents, ts);
199                 will_return(__wrap_io_getevents, &mock_events[off + ev_off]);
200                 ts = NULL;
201                 off += 128;
202                 nr -= 128;
203         }
204         if (nr == 0)
205                 will_return(__wrap_io_getevents, 0);
206         ev_off += i;
207 }
208
209 void do_check_state(struct checker *c, int sync, int timeout, int chk_state)
210 {
211         struct directio_context * ct = (struct directio_context *)c->context;
212
213         if (!ct->running)
214                 will_return(__wrap_io_submit, 1);
215         assert_int_equal(check_state(test_fd, ct, sync, timeout), chk_state);
216         assert_int_equal(ev_off, 0);
217         memset(mock_events, 0, sizeof(mock_events));
218 }
219
220 void do_libcheck_unload(int nr_aio_grps)
221 {
222         int count = 0;
223         struct aio_group *aio_grp;
224
225         list_for_each_entry(aio_grp, &aio_grp_list, node)
226                 count++;
227         assert_int_equal(count, nr_aio_grps);
228         for (count = 0; count < nr_aio_grps; count++)
229                 will_return(__wrap_io_destroy, 0);
230         libcheck_unload();
231         assert_true(list_empty(&aio_grp_list));
232         assert_int_equal(ioctx_count, 0);
233 }
234
235 static void do_libcheck_init(struct checker *c, int blocksize,
236                              struct async_req **req)
237 {
238         struct directio_context * ct;
239
240         c->fd = test_fd;
241         will_return(__wrap_ioctl, blocksize);
242         assert_int_equal(libcheck_init(c), 0);
243         ct = (struct directio_context *)c->context;
244         assert_non_null(ct);
245         assert_non_null(ct->aio_grp);
246         assert_non_null(ct->req);
247         if (req)
248                 *req = ct->req;
249 #ifndef DIO_TEST_DEV
250         /* don't check fake blocksize on real devices */
251         assert_int_equal(ct->req->blksize, blocksize);
252 #endif
253 }
254
255 static int is_checker_running(struct checker *c)
256 {
257         struct directio_context * ct = (struct directio_context *)c->context;
258         return ct->running;
259 }
260
261 static struct aio_group *get_aio_grp(struct checker *c)
262 {
263         struct directio_context * ct = (struct directio_context *)c->context;
264
265         assert_non_null(ct);
266         return ct->aio_grp;
267 }
268
269 static void check_aio_grp(struct aio_group *aio_grp, int holders,
270                           int orphans)
271 {
272         int count = 0;
273         struct list_head *item;
274
275         list_for_each(item, &aio_grp->orphans)
276                 count++;
277         assert_int_equal(holders, aio_grp->holders);
278         assert_int_equal(orphans, count);
279 }
280
281 static void do_libcheck_load(void)
282 {
283         int count = 0;
284         struct aio_group *aio_grp;
285
286         assert_true(list_empty(&aio_grp_list));
287         will_return(__wrap_io_setup, 0);
288         assert_int_equal(libcheck_load(), 0);
289         list_for_each_entry(aio_grp, &aio_grp_list, node) {
290                 assert_int_equal(aio_grp->holders, 0);
291                 count++;
292         }
293         assert_int_equal(count, 1);
294 }
295
296 /* simple loading resetting and unloading test */
297 static void test_load_reset_unload(void **state)
298 {
299         struct list_head *item;
300         do_libcheck_load();
301         item = aio_grp_list.next;
302         assert_int_equal(libcheck_reset(), 0);
303         assert_false(list_empty(&aio_grp_list));
304         assert_true(item == aio_grp_list.next);
305         do_libcheck_unload(1);
306 }
307
308 /* test initializing and then freeing 4096 checkers */
309 static void test_init_free(void **state)
310 {
311         int i, count = 0;
312         struct checker c[4096] = {0};
313         struct aio_group *aio_grp;
314
315         do_libcheck_load();
316         aio_grp = list_entry(aio_grp_list.next, typeof(*aio_grp), node);
317         will_return(__wrap_io_setup, 0);
318         will_return(__wrap_io_setup, 0);
319         will_return(__wrap_io_setup, 0);
320         for (i = 0; i < 4096; i++) {
321                 struct directio_context * ct;
322
323                 if (i % 3 == 0)
324                         do_libcheck_init(&c[i], 512, NULL);
325                 else if (i % 3 == 1)
326                         do_libcheck_init(&c[i], 1024, NULL);
327                 else
328                         do_libcheck_init(&c[i], 4096, NULL);
329                 ct = (struct directio_context *)c[i].context;
330                 assert_non_null(ct->aio_grp);
331                 if (i && (i & 1023) == 0)
332                         aio_grp = ct->aio_grp;
333                 else {
334                         assert_ptr_equal(ct->aio_grp, aio_grp);
335                         assert_int_equal(aio_grp->holders, (i & 1023) + 1);
336                 }
337         }
338         count = 0;
339         list_for_each_entry(aio_grp, &aio_grp_list, node)
340                 count++;
341         assert_int_equal(count, 4);
342         for (i = 0; i < 4096; i++) {
343                 struct directio_context * ct = (struct directio_context *)c[i].context;
344
345                 aio_grp = ct->aio_grp;
346                 libcheck_free(&c[i]);
347                 assert_int_equal(aio_grp->holders, 1023 - (i & 1023));
348         }
349         count = 0;
350         list_for_each_entry(aio_grp, &aio_grp_list, node) {
351                 assert_int_equal(aio_grp->holders, 0);
352                 count++;
353         }
354         assert_int_equal(count, 4);
355         will_return(__wrap_io_destroy, 0);
356         will_return(__wrap_io_destroy, 0);
357         will_return(__wrap_io_destroy, 0);
358         assert_int_equal(libcheck_reset(), 0);
359         do_libcheck_unload(1);
360 }
361
362 /* check mixed initializing and freeing 4096 checkers */
363 static void test_multi_init_free(void **state)
364 {
365         int i, count;
366         struct checker c[4096] = {0};
367         struct aio_group *aio_grp;
368
369         do_libcheck_load();
370         will_return(__wrap_io_setup, 0);
371         will_return(__wrap_io_setup, 0);
372         will_return(__wrap_io_setup, 0);
373         for (count = 0, i = 0; i < 4096; count++) {
374                 /* usually init, but occasionally free checkers */
375                 if (count == 0 || (count % 5 != 0 && count % 7 != 0)) {
376                         do_libcheck_init(&c[i], 4096, NULL);
377                         i++;
378                 } else {
379                         i--;
380                         libcheck_free(&c[i]);
381                 }
382         }
383         count = 0;
384         list_for_each_entry(aio_grp, &aio_grp_list, node) {
385                 assert_int_equal(aio_grp->holders, 1024);
386                 count++;
387         }
388         assert_int_equal(count, 4);
389         for (count = 0, i = 4096; i > 0; count++) {
390                 /* usually free, but occasionally init checkers */
391                 if (count == 0 || (count % 5 != 0 && count % 7 != 0)) {
392                         i--;
393                         libcheck_free(&c[i]);
394                 } else {
395                         do_libcheck_init(&c[i], 4096, NULL);
396                         i++;
397                 }
398         }
399         do_libcheck_unload(4);
400 }
401
402 /* simple single checker sync test */
403 static void test_check_state_simple(void **state)
404 {
405         struct checker c = {0};
406         struct async_req *req;
407         int res = 0;
408
409         do_libcheck_load();
410         do_libcheck_init(&c, 4096, &req);
411         return_io_getevents_nr(NULL, 1, &req, &res);
412         do_check_state(&c, 1, 30, PATH_UP);
413         libcheck_free(&c);
414         do_libcheck_unload(1);
415 }
416
417 /* test sync timeout */
418 static void test_check_state_timeout(void **state)
419 {
420         struct checker c = {0};
421         struct aio_group *aio_grp;
422
423         do_libcheck_load();
424         do_libcheck_init(&c, 4096, NULL);
425         aio_grp = get_aio_grp(&c);
426         return_io_getevents_none();
427         will_return(__wrap_io_cancel, 0);
428         do_check_state(&c, 1, 30, PATH_DOWN);
429         check_aio_grp(aio_grp, 1, 0);
430 #ifdef DIO_TEST_DEV
431         /* io_cancel will return negative value on timeout, so it happens again
432          * when freeing the checker */
433         will_return(__wrap_io_cancel, 0);
434 #endif
435         libcheck_free(&c);
436         do_libcheck_unload(1);
437 }
438
439 /* test async timeout */
440 static void test_check_state_async_timeout(void **state)
441 {
442         struct checker c = {0};
443         struct aio_group *aio_grp;
444
445         do_libcheck_load();
446         do_libcheck_init(&c, 4096, NULL);
447         aio_grp = get_aio_grp(&c);
448         return_io_getevents_none();
449         do_check_state(&c, 0, 3, PATH_PENDING);
450         return_io_getevents_none();
451         do_check_state(&c, 0, 3, PATH_PENDING);
452         return_io_getevents_none();
453         do_check_state(&c, 0, 3, PATH_PENDING);
454         return_io_getevents_none();
455         will_return(__wrap_io_cancel, 0);
456         do_check_state(&c, 0, 3, PATH_DOWN);
457         check_aio_grp(aio_grp, 1, 0);
458 #ifdef DIO_TEST_DEV
459         will_return(__wrap_io_cancel, 0);
460 #endif
461         libcheck_free(&c);
462         do_libcheck_unload(1);
463 }
464
465 /* test freeing checkers with outstanding requests */
466 static void test_free_with_pending(void **state)
467 {
468         struct checker c[2] = {0};
469         struct aio_group *aio_grp;
470         struct async_req *req;
471         int res = 0;
472
473         do_libcheck_load();
474         do_libcheck_init(&c[0], 4096, &req);
475         do_libcheck_init(&c[1], 4096, NULL);
476         aio_grp = get_aio_grp(c);
477         return_io_getevents_none();
478         do_check_state(&c[0], 0, 30, PATH_PENDING);
479         return_io_getevents_nr(NULL, 1, &req, &res);
480         return_io_getevents_none();
481         do_check_state(&c[1], 0, 30, PATH_PENDING);
482         assert_true(is_checker_running(&c[0]));
483         assert_true(is_checker_running(&c[1]));
484         check_aio_grp(aio_grp, 2, 0);
485         libcheck_free(&c[0]);
486         check_aio_grp(aio_grp, 1, 0);
487         will_return(__wrap_io_cancel, 0);
488         libcheck_free(&c[1]);
489 #ifdef DIO_TEST_DEV
490         check_aio_grp(aio_grp, 1, 1); /* real cancel doesn't remove request */
491 #else
492         check_aio_grp(aio_grp, 0, 0);
493 #endif
494         do_libcheck_unload(1);
495 }
496
497 /* test removing orpahed aio_group on free */
498 static void test_orphaned_aio_group(void **state)
499 {
500         struct checker c[AIO_GROUP_SIZE] = {0};
501         struct aio_group *aio_grp, *tmp_grp;
502         int i;
503
504         do_libcheck_load();
505         for (i = 0; i < AIO_GROUP_SIZE; i++) {
506                 do_libcheck_init(&c[i], 4096, NULL);
507                 return_io_getevents_none();
508                 do_check_state(&c[i], 0, 30, PATH_PENDING);
509         }
510         aio_grp = get_aio_grp(c);
511         check_aio_grp(aio_grp, AIO_GROUP_SIZE, 0);
512         i = 0;
513         list_for_each_entry(tmp_grp, &aio_grp_list, node)
514                 i++;
515         assert_int_equal(i, 1);
516         for (i = 0; i < AIO_GROUP_SIZE; i++) {
517                 assert_true(is_checker_running(&c[i]));
518                 will_return(__wrap_io_cancel, -1);
519                 if (i == AIO_GROUP_SIZE - 1) {
520                         /* remove the orphaned group and create a new one */
521                         will_return(__wrap_io_destroy, 0);
522                         will_return(__wrap_io_setup, 0);
523                 }
524                 libcheck_free(&c[i]);
525         }
526         i = 0;
527         list_for_each_entry(tmp_grp, &aio_grp_list, node) {
528                 i++;
529                 check_aio_grp(aio_grp, 0, 0);
530         }
531         assert_int_equal(i, 1);
532         do_libcheck_unload(1);
533 }
534
535 /* test sync timeout with failed cancel and cleanup by another
536  * checker */
537 static void test_timeout_cancel_failed(void **state)
538 {
539         struct checker c[2] = {0};
540         struct aio_group *aio_grp;
541         struct async_req *reqs[2];
542         int res[] = {0,0};
543         int i;
544
545         do_libcheck_load();
546         for (i = 0; i < 2; i++)
547                 do_libcheck_init(&c[i], 4096, &reqs[i]);
548         aio_grp = get_aio_grp(c);
549         return_io_getevents_none();
550         will_return(__wrap_io_cancel, -1);
551         do_check_state(&c[0], 1, 30, PATH_DOWN);
552         assert_true(is_checker_running(&c[0]));
553         check_aio_grp(aio_grp, 2, 0);
554         return_io_getevents_none();
555         will_return(__wrap_io_cancel, -1);
556         do_check_state(&c[0], 1, 30, PATH_DOWN);
557         assert_true(is_checker_running(&c[0]));
558         return_io_getevents_nr(NULL, 1, &reqs[0], &res[0]);
559         return_io_getevents_nr(NULL, 1, &reqs[1], &res[1]);
560         do_check_state(&c[1], 1, 30, PATH_UP);
561         do_check_state(&c[0], 1, 30, PATH_UP);
562         for (i = 0; i < 2; i++) {
563                 assert_false(is_checker_running(&c[i]));
564                 libcheck_free(&c[i]);
565         }
566         do_libcheck_unload(1);
567 }
568
569 /* test async timeout with failed cancel and cleanup by another
570  * checker */
571 static void test_async_timeout_cancel_failed(void **state)
572 {
573         struct checker c[2] = {0};
574         struct async_req *reqs[2];
575         int res[] = {0,0};
576         int i;
577
578         do_libcheck_load();
579         for (i = 0; i < 2; i++)
580                 do_libcheck_init(&c[i], 4096, &reqs[i]);
581         return_io_getevents_none();
582         do_check_state(&c[0], 0, 2, PATH_PENDING);
583         return_io_getevents_none();
584         do_check_state(&c[1], 0, 2, PATH_PENDING);
585         return_io_getevents_none();
586         do_check_state(&c[0], 0, 2, PATH_PENDING);
587         return_io_getevents_none();
588         do_check_state(&c[1], 0, 2, PATH_PENDING);
589         return_io_getevents_none();
590         will_return(__wrap_io_cancel, -1);
591         do_check_state(&c[0], 0, 2, PATH_DOWN);
592 #ifndef DIO_TEST_DEV
593         /* can't pick which even gets returned on real devices */
594         return_io_getevents_nr(NULL, 1, &reqs[1], &res[1]);
595         do_check_state(&c[1], 0, 2, PATH_UP);
596 #endif
597         return_io_getevents_none();
598         will_return(__wrap_io_cancel, -1);
599         do_check_state(&c[0], 0, 2, PATH_DOWN);
600         assert_true(is_checker_running(&c[0]));
601         return_io_getevents_nr(NULL, 2, reqs, res);
602         do_check_state(&c[1], 0, 2, PATH_UP);
603         do_check_state(&c[0], 0, 2, PATH_UP);
604         for (i = 0; i < 2; i++) {
605                 assert_false(is_checker_running(&c[i]));
606                 libcheck_free(&c[i]);
607         }
608         do_libcheck_unload(1);
609 }
610
611 /* test orphaning a request, and having another checker clean it up */
612 static void test_orphan_checker_cleanup(void **state)
613 {
614         struct checker c[2] = {0};
615         struct async_req *reqs[2];
616         int res[] = {0,0};
617         struct aio_group *aio_grp;
618         int i;
619
620         do_libcheck_load();
621         for (i = 0; i < 2; i++)
622                 do_libcheck_init(&c[i], 4096, &reqs[i]);
623         aio_grp = get_aio_grp(c);
624         return_io_getevents_none();
625         do_check_state(&c[0], 0, 30, PATH_PENDING);
626         will_return(__wrap_io_cancel, -1);
627         check_aio_grp(aio_grp, 2, 0);
628         libcheck_free(&c[0]);
629         check_aio_grp(aio_grp, 2, 1);
630         return_io_getevents_nr(NULL, 2, reqs, res);
631         do_check_state(&c[1], 0, 2, PATH_UP);
632         check_aio_grp(aio_grp, 1, 0);
633         libcheck_free(&c[1]);
634         check_aio_grp(aio_grp, 0, 0);
635         do_libcheck_unload(1);
636 }
637
638 /* test orphaning a request, and having reset clean it up */
639 static void test_orphan_reset_cleanup(void **state)
640 {
641         struct checker c;
642         struct aio_group *orphan_aio_grp, *tmp_aio_grp;
643         int found, count;
644
645         do_libcheck_load();
646         do_libcheck_init(&c, 4096, NULL);
647         orphan_aio_grp = get_aio_grp(&c);
648         return_io_getevents_none();
649         do_check_state(&c, 0, 30, PATH_PENDING);
650         will_return(__wrap_io_cancel, -1);
651         check_aio_grp(orphan_aio_grp, 1, 0);
652         libcheck_free(&c);
653         check_aio_grp(orphan_aio_grp, 1, 1);
654         found = count = 0;
655         list_for_each_entry(tmp_aio_grp, &aio_grp_list, node) {
656                 count++;
657                 if (tmp_aio_grp == orphan_aio_grp)
658                         found = 1;
659         }
660         assert_int_equal(count, 1);
661         assert_int_equal(found, 1);
662         will_return(__wrap_io_setup, 0);
663         will_return(__wrap_io_destroy, 0);
664         assert_int_equal(libcheck_reset(), 0);
665         found = count = 0;
666         list_for_each_entry(tmp_aio_grp, &aio_grp_list, node) {
667                 count++;
668                 check_aio_grp(tmp_aio_grp, 0, 0);
669                 if (tmp_aio_grp == orphan_aio_grp)
670                         found = 1;
671         }
672         assert_int_equal(count, 1);
673         assert_int_equal(found, 0);
674         do_libcheck_unload(1);
675 }
676
677 /* test orphaning a request, and having unload clean it up */
678 static void test_orphan_unload_cleanup(void **state)
679 {
680         struct checker c;
681         struct aio_group *orphan_aio_grp, *tmp_aio_grp;
682         int found, count;
683
684         do_libcheck_load();
685         do_libcheck_init(&c, 4096, NULL);
686         orphan_aio_grp = get_aio_grp(&c);
687         return_io_getevents_none();
688         do_check_state(&c, 0, 30, PATH_PENDING);
689         will_return(__wrap_io_cancel, -1);
690         check_aio_grp(orphan_aio_grp, 1, 0);
691         libcheck_free(&c);
692         check_aio_grp(orphan_aio_grp, 1, 1);
693         found = count = 0;
694         list_for_each_entry(tmp_aio_grp, &aio_grp_list, node) {
695                 count++;
696                 if (tmp_aio_grp == orphan_aio_grp)
697                         found = 1;
698         }
699         assert_int_equal(count, 1);
700         assert_int_equal(found, 1);
701         do_libcheck_unload(1);
702 }
703
704 /* test checkers with different blocksizes */
705 static void test_check_state_blksize(void **state)
706 {
707         int i;
708         struct checker c[3] = {0};
709         int blksize[] = {4096, 1024, 512};
710         struct async_req *reqs[3];
711         int res[] = {0,1,0};
712 #ifdef DIO_TEST_DEV
713         /* can't pick event return state on real devices */
714         int chk_state[] = {PATH_UP, PATH_UP, PATH_UP};
715 #else
716         int chk_state[] = {PATH_UP, PATH_DOWN, PATH_UP};
717 #endif
718
719         do_libcheck_load();
720         for (i = 0; i < 3; i++)
721                 do_libcheck_init(&c[i], blksize[i], &reqs[i]);
722         for (i = 0; i < 3; i++) {
723                 return_io_getevents_nr(NULL, 1, &reqs[i], &res[i]);
724                 do_check_state(&c[i], 1, 30, chk_state[i]);
725         }
726         for (i = 0; i < 3; i++) {
727                 assert_false(is_checker_running(&c[i]));
728                 libcheck_free(&c[i]);
729         }
730         do_libcheck_unload(1);
731 }
732
733 /* test async checkers pending and getting resovled by another checker
734  * as well as the loops for getting multiple events */
735 static void test_check_state_async(void **state)
736 {
737         int i;
738         struct checker c[257] = {0};
739         struct async_req *reqs[257];
740         int res[257] = {0};
741
742         do_libcheck_load();
743         for (i = 0; i < 257; i++)
744                 do_libcheck_init(&c[i], 4096, &reqs[i]);
745         for (i = 0; i < 256; i++) {
746                 return_io_getevents_none();
747                 do_check_state(&c[i], 0, 30, PATH_PENDING);
748                 assert_true(is_checker_running(&c[i]));
749         }
750         return_io_getevents_nr(&full_timeout, 256, reqs, res);
751         return_io_getevents_nr(NULL, 1, &reqs[256], &res[256]);
752         do_check_state(&c[256], 0, 30, PATH_UP);
753         assert_false(is_checker_running(&c[256]));
754         libcheck_free(&c[256]);
755         for (i = 0; i < 256; i++) {
756                 do_check_state(&c[i], 0, 30, PATH_UP);
757                 assert_false(is_checker_running(&c[i]));
758                 libcheck_free(&c[i]);
759         }
760         do_libcheck_unload(1);
761 }
762
763 static int setup(void **state)
764 {
765 #ifdef DIO_TEST_DEV
766         test_fd = open(DIO_TEST_DEV, O_RDONLY);
767         if (test_fd < 0)
768                 fail_msg("cannot open %s: %m", DIO_TEST_DEV);
769 #endif
770         return 0;
771 }
772
773 static int teardown(void **state)
774 {
775 #ifdef DIO_TEST_DEV
776         assert_true(test_fd > 0);
777         assert_int_equal(close(test_fd), 0);
778 #endif
779         return 0;
780 }
781
782 int test_directio(void)
783 {
784         const struct CMUnitTest tests[] = {
785                 cmocka_unit_test(test_load_reset_unload),
786                 cmocka_unit_test(test_init_free),
787                 cmocka_unit_test(test_multi_init_free),
788                 cmocka_unit_test(test_check_state_simple),
789                 cmocka_unit_test(test_check_state_timeout),
790                 cmocka_unit_test(test_check_state_async_timeout),
791                 cmocka_unit_test(test_free_with_pending),
792                 cmocka_unit_test(test_timeout_cancel_failed),
793                 cmocka_unit_test(test_async_timeout_cancel_failed),
794                 cmocka_unit_test(test_orphan_checker_cleanup),
795                 cmocka_unit_test(test_orphan_reset_cleanup),
796                 cmocka_unit_test(test_orphan_unload_cleanup),
797                 cmocka_unit_test(test_check_state_blksize),
798                 cmocka_unit_test(test_check_state_async),
799                 cmocka_unit_test(test_orphaned_aio_group),
800         };
801
802         return cmocka_run_group_tests(tests, setup, teardown);
803 }
804
805 int main(void)
806 {
807         int ret = 0;
808
809         conf.verbosity = 2;
810         ret += test_directio();
811         return ret;
812 }