libmultipath: change loading and resetting in directio
[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_reset(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_reset();
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 /* simple resetting test */
282 static void test_reset(void **state)
283 {
284         assert_true(list_empty(&aio_grp_list));
285         do_libcheck_reset(0);
286 }
287
288 /* tests initializing, then resetting, and then initializing again */
289 static void test_init_reset_init(void **state)
290 {
291         struct checker c = {0};
292         struct aio_group *aio_grp, *tmp_grp;
293
294         assert_true(list_empty(&aio_grp_list));
295         will_return(__wrap_io_setup, 0);
296         do_libcheck_init(&c, 4096, NULL);
297         aio_grp = get_aio_grp(&c);
298         check_aio_grp(aio_grp, 1, 0);
299         list_for_each_entry(tmp_grp, &aio_grp_list, node)
300                 assert_ptr_equal(aio_grp, tmp_grp);
301         libcheck_free(&c);
302         check_aio_grp(aio_grp, 0, 0);
303         do_libcheck_reset(1);
304         will_return(__wrap_io_setup, 0);
305         do_libcheck_init(&c, 4096, NULL);
306         aio_grp = get_aio_grp(&c);
307         check_aio_grp(aio_grp, 1, 0);
308         list_for_each_entry(tmp_grp, &aio_grp_list, node)
309                 assert_ptr_equal(aio_grp, tmp_grp);
310         libcheck_free(&c);
311         check_aio_grp(aio_grp, 0, 0);
312         do_libcheck_reset(1);
313 }
314
315 /* test initializing and then freeing 4096 checkers */
316 static void test_init_free(void **state)
317 {
318         int i, count = 0;
319         struct checker c[4096] = {0};
320         struct aio_group *aio_grp;
321
322         assert_true(list_empty(&aio_grp_list));
323         will_return(__wrap_io_setup, 0);
324         will_return(__wrap_io_setup, 0);
325         will_return(__wrap_io_setup, 0);
326         will_return(__wrap_io_setup, 0);
327         for (i = 0; i < 4096; i++) {
328                 struct directio_context * ct;
329
330                 if (i % 3 == 0)
331                         do_libcheck_init(&c[i], 512, NULL);
332                 else if (i % 3 == 1)
333                         do_libcheck_init(&c[i], 1024, NULL);
334                 else
335                         do_libcheck_init(&c[i], 4096, NULL);
336                 ct = (struct directio_context *)c[i].context;
337                 assert_non_null(ct->aio_grp);
338                 if ((i & 1023) == 0)
339                         aio_grp = ct->aio_grp;
340                 else {
341                         assert_ptr_equal(ct->aio_grp, aio_grp);
342                         assert_int_equal(aio_grp->holders, (i & 1023) + 1);
343                 }
344         }
345         count = 0;
346         list_for_each_entry(aio_grp, &aio_grp_list, node)
347                 count++;
348         assert_int_equal(count, 4);
349         for (i = 0; i < 4096; i++) {
350                 struct directio_context * ct = (struct directio_context *)c[i].context;
351
352                 aio_grp = ct->aio_grp;
353                 libcheck_free(&c[i]);
354                 assert_int_equal(aio_grp->holders, 1023 - (i & 1023));
355         }
356         list_for_each_entry(aio_grp, &aio_grp_list, node)
357                 assert_int_equal(aio_grp->holders, 0);
358         do_libcheck_reset(4);
359 }
360
361 /* check mixed initializing and freeing 4096 checkers */
362 static void test_multi_init_free(void **state)
363 {
364         int i, count;
365         struct checker c[4096] = {0};
366         struct aio_group *aio_grp;
367
368         assert_true(list_empty(&aio_grp_list));
369         will_return(__wrap_io_setup, 0);
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_reset(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         assert_true(list_empty(&aio_grp_list));
410         will_return(__wrap_io_setup, 0);
411         do_libcheck_init(&c, 4096, &req);
412         return_io_getevents_nr(NULL, 1, &req, &res);
413         do_check_state(&c, 1, 30, PATH_UP);
414         libcheck_free(&c);
415         do_libcheck_reset(1);
416 }
417
418 /* test sync timeout */
419 static void test_check_state_timeout(void **state)
420 {
421         struct checker c = {0};
422         struct aio_group *aio_grp;
423
424         assert_true(list_empty(&aio_grp_list));
425         will_return(__wrap_io_setup, 0);
426         do_libcheck_init(&c, 4096, NULL);
427         aio_grp = get_aio_grp(&c);
428         return_io_getevents_none();
429         will_return(__wrap_io_cancel, 0);
430         do_check_state(&c, 1, 30, PATH_DOWN);
431         check_aio_grp(aio_grp, 1, 0);
432 #ifdef DIO_TEST_DEV
433         /* io_cancel will return negative value on timeout, so it happens again
434          * when freeing the checker */
435         will_return(__wrap_io_cancel, 0);
436 #endif
437         libcheck_free(&c);
438         do_libcheck_reset(1);
439 }
440
441 /* test async timeout */
442 static void test_check_state_async_timeout(void **state)
443 {
444         struct checker c = {0};
445         struct aio_group *aio_grp;
446
447         assert_true(list_empty(&aio_grp_list));
448         will_return(__wrap_io_setup, 0);
449         do_libcheck_init(&c, 4096, NULL);
450         aio_grp = get_aio_grp(&c);
451         return_io_getevents_none();
452         do_check_state(&c, 0, 3, PATH_PENDING);
453         return_io_getevents_none();
454         do_check_state(&c, 0, 3, PATH_PENDING);
455         return_io_getevents_none();
456         do_check_state(&c, 0, 3, PATH_PENDING);
457         return_io_getevents_none();
458         will_return(__wrap_io_cancel, 0);
459         do_check_state(&c, 0, 3, PATH_DOWN);
460         check_aio_grp(aio_grp, 1, 0);
461 #ifdef DIO_TEST_DEV
462         will_return(__wrap_io_cancel, 0);
463 #endif
464         libcheck_free(&c);
465         do_libcheck_reset(1);
466 }
467
468 /* test freeing checkers with outstanding requests */
469 static void test_free_with_pending(void **state)
470 {
471         struct checker c[2] = {0};
472         struct aio_group *aio_grp;
473         struct async_req *req;
474         int res = 0;
475
476         assert_true(list_empty(&aio_grp_list));
477         will_return(__wrap_io_setup, 0);
478         do_libcheck_init(&c[0], 4096, &req);
479         do_libcheck_init(&c[1], 4096, NULL);
480         aio_grp = get_aio_grp(c);
481         return_io_getevents_none();
482         do_check_state(&c[0], 0, 30, PATH_PENDING);
483         return_io_getevents_nr(NULL, 1, &req, &res);
484         return_io_getevents_none();
485         do_check_state(&c[1], 0, 30, PATH_PENDING);
486         assert_true(is_checker_running(&c[0]));
487         assert_true(is_checker_running(&c[1]));
488         check_aio_grp(aio_grp, 2, 0);
489         libcheck_free(&c[0]);
490         check_aio_grp(aio_grp, 1, 0);
491         will_return(__wrap_io_cancel, 0);
492         libcheck_free(&c[1]);
493 #ifdef DIO_TEST_DEV
494         check_aio_grp(aio_grp, 1, 1); /* real cancel doesn't remove request */
495 #else
496         check_aio_grp(aio_grp, 0, 0);
497 #endif
498         do_libcheck_reset(1);
499 }
500
501 /* test removing orpahed aio_group on free */
502 static void test_orphaned_aio_group(void **state)
503 {
504         struct checker c[AIO_GROUP_SIZE] = {0};
505         struct aio_group *aio_grp, *tmp_grp;
506         int i;
507
508         assert_true(list_empty(&aio_grp_list));
509         will_return(__wrap_io_setup, 0);
510         for (i = 0; i < AIO_GROUP_SIZE; i++) {
511                 do_libcheck_init(&c[i], 4096, NULL);
512                 return_io_getevents_none();
513                 do_check_state(&c[i], 0, 30, PATH_PENDING);
514         }
515         aio_grp = get_aio_grp(c);
516         check_aio_grp(aio_grp, AIO_GROUP_SIZE, 0);
517         i = 0;
518         list_for_each_entry(tmp_grp, &aio_grp_list, node)
519                 i++;
520         assert_int_equal(i, 1);
521         for (i = 0; i < AIO_GROUP_SIZE; i++) {
522                 assert_true(is_checker_running(&c[i]));
523                 will_return(__wrap_io_cancel, -1);
524                 if (i == AIO_GROUP_SIZE - 1) {
525                         /* remove the orphaned group and create a new one */
526                         will_return(__wrap_io_destroy, 0);
527                 }
528                 libcheck_free(&c[i]);
529         }
530         do_libcheck_reset(0);
531 }
532
533 /* test sync timeout with failed cancel and cleanup by another
534  * checker */
535 static void test_timeout_cancel_failed(void **state)
536 {
537         struct checker c[2] = {0};
538         struct aio_group *aio_grp;
539         struct async_req *reqs[2];
540         int res[] = {0,0};
541         int i;
542
543         assert_true(list_empty(&aio_grp_list));
544         will_return(__wrap_io_setup, 0);
545         for (i = 0; i < 2; i++)
546                 do_libcheck_init(&c[i], 4096, &reqs[i]);
547         aio_grp = get_aio_grp(c);
548         return_io_getevents_none();
549         will_return(__wrap_io_cancel, -1);
550         do_check_state(&c[0], 1, 30, PATH_DOWN);
551         assert_true(is_checker_running(&c[0]));
552         check_aio_grp(aio_grp, 2, 0);
553         return_io_getevents_none();
554         will_return(__wrap_io_cancel, -1);
555         do_check_state(&c[0], 1, 30, PATH_DOWN);
556         assert_true(is_checker_running(&c[0]));
557         return_io_getevents_nr(NULL, 1, &reqs[0], &res[0]);
558         return_io_getevents_nr(NULL, 1, &reqs[1], &res[1]);
559         do_check_state(&c[1], 1, 30, PATH_UP);
560         do_check_state(&c[0], 1, 30, PATH_UP);
561         for (i = 0; i < 2; i++) {
562                 assert_false(is_checker_running(&c[i]));
563                 libcheck_free(&c[i]);
564         }
565         do_libcheck_reset(1);
566 }
567
568 /* test async timeout with failed cancel and cleanup by another
569  * checker */
570 static void test_async_timeout_cancel_failed(void **state)
571 {
572         struct checker c[2] = {0};
573         struct async_req *reqs[2];
574         int res[] = {0,0};
575         int i;
576
577         assert_true(list_empty(&aio_grp_list));
578         will_return(__wrap_io_setup, 0);
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_reset(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         assert_true(list_empty(&aio_grp_list));
621         will_return(__wrap_io_setup, 0);
622         for (i = 0; i < 2; i++)
623                 do_libcheck_init(&c[i], 4096, &reqs[i]);
624         aio_grp = get_aio_grp(c);
625         return_io_getevents_none();
626         do_check_state(&c[0], 0, 30, PATH_PENDING);
627         will_return(__wrap_io_cancel, -1);
628         check_aio_grp(aio_grp, 2, 0);
629         libcheck_free(&c[0]);
630         check_aio_grp(aio_grp, 2, 1);
631         return_io_getevents_nr(NULL, 2, reqs, res);
632         do_check_state(&c[1], 0, 2, PATH_UP);
633         check_aio_grp(aio_grp, 1, 0);
634         libcheck_free(&c[1]);
635         check_aio_grp(aio_grp, 0, 0);
636         do_libcheck_reset(1);
637 }
638
639 /* test orphaning a request, and having reset clean it up */
640 static void test_orphan_reset_cleanup(void **state)
641 {
642         struct checker c;
643         struct aio_group *orphan_aio_grp, *tmp_aio_grp;
644         int found, count;
645
646         assert_true(list_empty(&aio_grp_list));
647         will_return(__wrap_io_setup, 0);
648         do_libcheck_init(&c, 4096, NULL);
649         orphan_aio_grp = get_aio_grp(&c);
650         return_io_getevents_none();
651         do_check_state(&c, 0, 30, PATH_PENDING);
652         will_return(__wrap_io_cancel, -1);
653         check_aio_grp(orphan_aio_grp, 1, 0);
654         libcheck_free(&c);
655         check_aio_grp(orphan_aio_grp, 1, 1);
656         found = count = 0;
657         list_for_each_entry(tmp_aio_grp, &aio_grp_list, node) {
658                 count++;
659                 if (tmp_aio_grp == orphan_aio_grp)
660                         found = 1;
661         }
662         assert_int_equal(count, 1);
663         assert_int_equal(found, 1);
664         do_libcheck_reset(1);
665 }
666
667 /* test checkers with different blocksizes */
668 static void test_check_state_blksize(void **state)
669 {
670         int i;
671         struct checker c[3] = {0};
672         int blksize[] = {4096, 1024, 512};
673         struct async_req *reqs[3];
674         int res[] = {0,1,0};
675 #ifdef DIO_TEST_DEV
676         /* can't pick event return state on real devices */
677         int chk_state[] = {PATH_UP, PATH_UP, PATH_UP};
678 #else
679         int chk_state[] = {PATH_UP, PATH_DOWN, PATH_UP};
680 #endif
681
682         assert_true(list_empty(&aio_grp_list));
683         will_return(__wrap_io_setup, 0);
684         for (i = 0; i < 3; i++)
685                 do_libcheck_init(&c[i], blksize[i], &reqs[i]);
686         for (i = 0; i < 3; i++) {
687                 return_io_getevents_nr(NULL, 1, &reqs[i], &res[i]);
688                 do_check_state(&c[i], 1, 30, chk_state[i]);
689         }
690         for (i = 0; i < 3; i++) {
691                 assert_false(is_checker_running(&c[i]));
692                 libcheck_free(&c[i]);
693         }
694         do_libcheck_reset(1);
695 }
696
697 /* test async checkers pending and getting resovled by another checker
698  * as well as the loops for getting multiple events */
699 static void test_check_state_async(void **state)
700 {
701         int i;
702         struct checker c[257] = {0};
703         struct async_req *reqs[257];
704         int res[257] = {0};
705
706         assert_true(list_empty(&aio_grp_list));
707         will_return(__wrap_io_setup, 0);
708         for (i = 0; i < 257; i++)
709                 do_libcheck_init(&c[i], 4096, &reqs[i]);
710         for (i = 0; i < 256; i++) {
711                 return_io_getevents_none();
712                 do_check_state(&c[i], 0, 30, PATH_PENDING);
713                 assert_true(is_checker_running(&c[i]));
714         }
715         return_io_getevents_nr(&full_timeout, 256, reqs, res);
716         return_io_getevents_nr(NULL, 1, &reqs[256], &res[256]);
717         do_check_state(&c[256], 0, 30, PATH_UP);
718         assert_false(is_checker_running(&c[256]));
719         libcheck_free(&c[256]);
720         for (i = 0; i < 256; i++) {
721                 do_check_state(&c[i], 0, 30, PATH_UP);
722                 assert_false(is_checker_running(&c[i]));
723                 libcheck_free(&c[i]);
724         }
725         do_libcheck_reset(1);
726 }
727
728 static int setup(void **state)
729 {
730 #ifdef DIO_TEST_DEV
731         test_fd = open(DIO_TEST_DEV, O_RDONLY);
732         if (test_fd < 0)
733                 fail_msg("cannot open %s: %m", DIO_TEST_DEV);
734 #endif
735         return 0;
736 }
737
738 static int teardown(void **state)
739 {
740 #ifdef DIO_TEST_DEV
741         assert_true(test_fd > 0);
742         assert_int_equal(close(test_fd), 0);
743 #endif
744         return 0;
745 }
746
747 int test_directio(void)
748 {
749         const struct CMUnitTest tests[] = {
750                 cmocka_unit_test(test_reset),
751                 cmocka_unit_test(test_init_reset_init),
752                 cmocka_unit_test(test_init_free),
753                 cmocka_unit_test(test_multi_init_free),
754                 cmocka_unit_test(test_check_state_simple),
755                 cmocka_unit_test(test_check_state_timeout),
756                 cmocka_unit_test(test_check_state_async_timeout),
757                 cmocka_unit_test(test_free_with_pending),
758                 cmocka_unit_test(test_timeout_cancel_failed),
759                 cmocka_unit_test(test_async_timeout_cancel_failed),
760                 cmocka_unit_test(test_orphan_checker_cleanup),
761                 cmocka_unit_test(test_orphan_reset_cleanup),
762                 cmocka_unit_test(test_check_state_blksize),
763                 cmocka_unit_test(test_check_state_async),
764                 cmocka_unit_test(test_orphaned_aio_group),
765         };
766
767         return cmocka_run_group_tests(tests, setup, teardown);
768 }
769
770 int main(void)
771 {
772         int ret = 0;
773
774         conf.verbosity = 2;
775         ret += test_directio();
776         return ret;
777 }