block: Add BDRV_REQ_NO_FALLBACK
[qemu/ar7.git] / tests / test-util-filemonitor.c
blob5d95cea5ee3571171d015f5558d1c3bf895fc6e8
1 /*
2 * Tests for util/filemonitor-*.c
4 * Copyright 2018 Red Hat, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
22 #include "qemu/main-loop.h"
23 #include "qapi/error.h"
24 #include "qemu/filemonitor.h"
26 #include <utime.h>
28 enum {
29 QFILE_MONITOR_TEST_OP_CREATE,
30 QFILE_MONITOR_TEST_OP_APPEND,
31 QFILE_MONITOR_TEST_OP_TRUNC,
32 QFILE_MONITOR_TEST_OP_RENAME,
33 QFILE_MONITOR_TEST_OP_TOUCH,
34 QFILE_MONITOR_TEST_OP_UNLINK,
37 typedef struct {
38 int type;
39 const char *filesrc;
40 const char *filedst;
41 } QFileMonitorTestOp;
43 typedef struct {
44 const char *file;
45 } QFileMonitorTestWatch;
47 typedef struct {
48 gsize nwatches;
49 const QFileMonitorTestWatch *watches;
51 gsize nops;
52 const QFileMonitorTestOp *ops;
53 } QFileMonitorTestPlan;
55 typedef struct {
56 int id;
57 QFileMonitorEvent event;
58 char *filename;
59 } QFileMonitorTestRecord;
62 typedef struct {
63 QemuMutex lock;
64 GList *records;
65 } QFileMonitorTestData;
67 static QemuMutex evlock;
68 static bool evstopping;
69 static bool evrunning;
72 * Main function for a background thread that is
73 * running the event loop during the test
75 static void *
76 qemu_file_monitor_test_event_loop(void *opaque G_GNUC_UNUSED)
78 qemu_mutex_lock(&evlock);
80 while (!evstopping) {
81 qemu_mutex_unlock(&evlock);
82 main_loop_wait(true);
83 qemu_mutex_lock(&evlock);
86 evrunning = false;
87 qemu_mutex_unlock(&evlock);
88 return NULL;
93 * File monitor event handler which simply maintains
94 * an ordered list of all events that it receives
96 static void
97 qemu_file_monitor_test_handler(int id,
98 QFileMonitorEvent event,
99 const char *filename,
100 void *opaque)
102 QFileMonitorTestData *data = opaque;
103 QFileMonitorTestRecord *rec = g_new0(QFileMonitorTestRecord, 1);
105 rec->id = id;
106 rec->event = event;
107 rec->filename = g_strdup(filename);
109 qemu_mutex_lock(&data->lock);
110 data->records = g_list_append(data->records, rec);
111 qemu_mutex_unlock(&data->lock);
115 static void
116 qemu_file_monitor_test_record_free(QFileMonitorTestRecord *rec)
118 g_free(rec->filename);
119 g_free(rec);
124 * Get the next event record that has been received by
125 * the file monitor event handler. Since events are
126 * emitted in the background thread running the event
127 * loop, we can't assume there is a record available
128 * immediately. Thus we will sleep for upto 5 seconds
129 * to wait for the event to be queued for us.
131 static QFileMonitorTestRecord *
132 qemu_file_monitor_test_next_record(QFileMonitorTestData *data)
134 GTimer *timer = g_timer_new();
135 QFileMonitorTestRecord *record = NULL;
136 GList *tmp;
138 qemu_mutex_lock(&data->lock);
139 while (!data->records && g_timer_elapsed(timer, NULL) < 5) {
140 qemu_mutex_unlock(&data->lock);
141 usleep(10 * 1000);
142 qemu_mutex_lock(&data->lock);
144 if (data->records) {
145 record = data->records->data;
146 tmp = data->records;
147 data->records = g_list_remove_link(data->records, tmp);
148 g_list_free(tmp);
150 qemu_mutex_unlock(&data->lock);
152 g_timer_destroy(timer);
153 return record;
158 * Check whether the event record we retrieved matches
159 * data we were expecting to see for the event
161 static bool
162 qemu_file_monitor_test_expect(QFileMonitorTestData *data,
163 int id,
164 QFileMonitorEvent event,
165 const char *filename)
167 QFileMonitorTestRecord *rec;
168 bool ret = false;
170 rec = qemu_file_monitor_test_next_record(data);
172 if (!rec) {
173 g_printerr("Missing event watch id %d event %d file %s\n",
174 id, event, filename);
175 return false;
178 if (id != rec->id) {
179 g_printerr("Expected watch id %d but got %d\n", id, rec->id);
180 goto cleanup;
183 if (event != rec->event) {
184 g_printerr("Expected event %d but got %d\n", event, rec->event);
185 goto cleanup;
188 if (!g_str_equal(filename, rec->filename)) {
189 g_printerr("Expected filename %s but got %s\n",
190 filename, rec->filename);
191 goto cleanup;
194 ret = true;
196 cleanup:
197 qemu_file_monitor_test_record_free(rec);
198 return ret;
202 static void
203 test_file_monitor_events(const void *opaque)
205 const QFileMonitorTestPlan *plan = opaque;
206 Error *local_err = NULL;
207 GError *gerr = NULL;
208 QFileMonitor *mon = qemu_file_monitor_new(&local_err);
209 QemuThread th;
210 GTimer *timer;
211 gchar *dir = NULL;
212 int err = -1;
213 gsize i, j;
214 char *pathsrc = NULL;
215 char *pathdst = NULL;
216 QFileMonitorTestData data;
218 qemu_mutex_init(&data.lock);
219 data.records = NULL;
222 * The file monitor needs the main loop running in
223 * order to receive events from inotify. We must
224 * thus spawn a background thread to run an event
225 * loop impl, while this thread triggers the
226 * actual file operations we're testing
228 evrunning = 1;
229 evstopping = 0;
230 qemu_thread_create(&th, "event-loop",
231 qemu_file_monitor_test_event_loop, NULL,
232 QEMU_THREAD_JOINABLE);
234 if (local_err) {
235 g_printerr("File monitoring not available: %s",
236 error_get_pretty(local_err));
237 error_free(local_err);
238 return;
241 dir = g_dir_make_tmp("test-util-filemonitor-XXXXXX",
242 &gerr);
243 if (!dir) {
244 g_printerr("Unable to create tmp dir %s",
245 gerr->message);
246 g_error_free(gerr);
247 abort();
251 * First register all the directory / file watches
252 * we're interested in seeing events against
254 for (i = 0; i < plan->nwatches; i++) {
255 int watchid;
256 watchid = qemu_file_monitor_add_watch(mon,
257 dir,
258 plan->watches[i].file,
259 qemu_file_monitor_test_handler,
260 &data,
261 &local_err);
262 if (watchid < 0) {
263 g_printerr("Unable to add watch %s",
264 error_get_pretty(local_err));
265 goto cleanup;
271 * Now invoke all the file operations (create,
272 * delete, rename, chmod, etc). These operations
273 * will trigger the various file monitor events
275 for (i = 0; i < plan->nops; i++) {
276 const QFileMonitorTestOp *op = &(plan->ops[i]);
277 int fd;
278 struct utimbuf ubuf;
280 pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc);
281 if (op->filedst) {
282 pathdst = g_strdup_printf("%s/%s", dir, op->filedst);
285 switch (op->type) {
286 case QFILE_MONITOR_TEST_OP_CREATE:
287 fd = open(pathsrc, O_WRONLY | O_CREAT, 0700);
288 if (fd < 0) {
289 g_printerr("Unable to create %s: %s",
290 pathsrc, strerror(errno));
291 goto cleanup;
293 close(fd);
294 break;
296 case QFILE_MONITOR_TEST_OP_APPEND:
297 fd = open(pathsrc, O_WRONLY | O_APPEND, 0700);
298 if (fd < 0) {
299 g_printerr("Unable to open %s: %s",
300 pathsrc, strerror(errno));
301 goto cleanup;
304 if (write(fd, "Hello World", 10) != 10) {
305 g_printerr("Unable to write %s: %s",
306 pathsrc, strerror(errno));
307 close(fd);
308 goto cleanup;
310 close(fd);
311 break;
313 case QFILE_MONITOR_TEST_OP_TRUNC:
314 if (truncate(pathsrc, 4) < 0) {
315 g_printerr("Unable to truncate %s: %s",
316 pathsrc, strerror(errno));
317 goto cleanup;
319 break;
321 case QFILE_MONITOR_TEST_OP_RENAME:
322 if (rename(pathsrc, pathdst) < 0) {
323 g_printerr("Unable to rename %s to %s: %s",
324 pathsrc, pathdst, strerror(errno));
325 goto cleanup;
327 break;
329 case QFILE_MONITOR_TEST_OP_UNLINK:
330 if (unlink(pathsrc) < 0) {
331 g_printerr("Unable to unlink %s: %s",
332 pathsrc, strerror(errno));
333 goto cleanup;
335 break;
337 case QFILE_MONITOR_TEST_OP_TOUCH:
338 ubuf.actime = 1024;
339 ubuf.modtime = 1025;
340 if (utime(pathsrc, &ubuf) < 0) {
341 g_printerr("Unable to touch %s: %s",
342 pathsrc, strerror(errno));
343 goto cleanup;
345 break;
347 default:
348 g_assert_not_reached();
351 g_free(pathsrc);
352 g_free(pathdst);
353 pathsrc = pathdst = NULL;
358 * Finally validate that we have received all the events
359 * we expect to see for the combination of watches and
360 * file operations
362 for (i = 0; i < plan->nops; i++) {
363 const QFileMonitorTestOp *op = &(plan->ops[i]);
365 switch (op->type) {
366 case QFILE_MONITOR_TEST_OP_CREATE:
367 for (j = 0; j < plan->nwatches; j++) {
368 if (plan->watches[j].file &&
369 !g_str_equal(plan->watches[j].file, op->filesrc))
370 continue;
372 if (!qemu_file_monitor_test_expect(
373 &data, j, QFILE_MONITOR_EVENT_CREATED, op->filesrc))
374 goto cleanup;
376 break;
378 case QFILE_MONITOR_TEST_OP_APPEND:
379 case QFILE_MONITOR_TEST_OP_TRUNC:
380 for (j = 0; j < plan->nwatches; j++) {
381 if (plan->watches[j].file &&
382 !g_str_equal(plan->watches[j].file, op->filesrc))
383 continue;
385 if (!qemu_file_monitor_test_expect(
386 &data, j, QFILE_MONITOR_EVENT_MODIFIED, op->filesrc))
387 goto cleanup;
389 break;
391 case QFILE_MONITOR_TEST_OP_RENAME:
392 for (j = 0; j < plan->nwatches; j++) {
393 if (plan->watches[j].file &&
394 !g_str_equal(plan->watches[j].file, op->filesrc))
395 continue;
397 if (!qemu_file_monitor_test_expect(
398 &data, j, QFILE_MONITOR_EVENT_DELETED, op->filesrc))
399 goto cleanup;
402 for (j = 0; j < plan->nwatches; j++) {
403 if (plan->watches[j].file &&
404 !g_str_equal(plan->watches[j].file, op->filedst))
405 continue;
407 if (!qemu_file_monitor_test_expect(
408 &data, j, QFILE_MONITOR_EVENT_CREATED, op->filedst))
409 goto cleanup;
411 break;
413 case QFILE_MONITOR_TEST_OP_TOUCH:
414 for (j = 0; j < plan->nwatches; j++) {
415 if (plan->watches[j].file &&
416 !g_str_equal(plan->watches[j].file, op->filesrc))
417 continue;
419 if (!qemu_file_monitor_test_expect(
420 &data, j, QFILE_MONITOR_EVENT_ATTRIBUTES, op->filesrc))
421 goto cleanup;
423 break;
425 case QFILE_MONITOR_TEST_OP_UNLINK:
426 for (j = 0; j < plan->nwatches; j++) {
427 if (plan->watches[j].file &&
428 !g_str_equal(plan->watches[j].file, op->filesrc))
429 continue;
431 if (!qemu_file_monitor_test_expect(
432 &data, j, QFILE_MONITOR_EVENT_DELETED, op->filesrc))
433 goto cleanup;
435 break;
437 default:
438 g_assert_not_reached();
442 err = 0;
444 cleanup:
445 g_free(pathsrc);
446 g_free(pathdst);
448 qemu_mutex_lock(&evlock);
449 evstopping = 1;
450 timer = g_timer_new();
451 while (evrunning && g_timer_elapsed(timer, NULL) < 5) {
452 qemu_mutex_unlock(&evlock);
453 usleep(10 * 1000);
454 qemu_mutex_lock(&evlock);
456 qemu_mutex_unlock(&evlock);
458 if (g_timer_elapsed(timer, NULL) >= 5) {
459 g_printerr("Event loop failed to quit after 5 seconds\n");
461 g_timer_destroy(timer);
463 for (i = 0; i < plan->nops; i++) {
464 const QFileMonitorTestOp *op = &(plan->ops[i]);
465 pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc);
466 unlink(pathsrc);
467 g_free(pathsrc);
468 if (op->filedst) {
469 pathdst = g_strdup_printf("%s/%s", dir, op->filedst);
470 unlink(pathdst);
471 g_free(pathdst);
475 qemu_file_monitor_free(mon);
476 g_list_foreach(data.records,
477 (GFunc)qemu_file_monitor_test_record_free, NULL);
478 g_list_free(data.records);
479 qemu_mutex_destroy(&data.lock);
480 if (dir) {
481 rmdir(dir);
483 g_free(dir);
484 g_assert(err == 0);
489 * Set of structs which define which file name patterns
490 * we're trying to watch against. NULL, means all files
491 * in the directory
493 static const QFileMonitorTestWatch watches_any[] = {
494 { NULL },
497 static const QFileMonitorTestWatch watches_one[] = {
498 { "one.txt" },
501 static const QFileMonitorTestWatch watches_two[] = {
502 { "two.txt" },
505 static const QFileMonitorTestWatch watches_many[] = {
506 { NULL },
507 { "one.txt" },
508 { "two.txt" },
513 * Various sets of file operations we're going to
514 * trigger and validate events for
516 static const QFileMonitorTestOp ops_create_one[] = {
517 { .type = QFILE_MONITOR_TEST_OP_CREATE,
518 .filesrc = "one.txt", }
521 static const QFileMonitorTestOp ops_delete_one[] = {
522 { .type = QFILE_MONITOR_TEST_OP_CREATE,
523 .filesrc = "one.txt", },
524 { .type = QFILE_MONITOR_TEST_OP_UNLINK,
525 .filesrc = "one.txt", }
528 static const QFileMonitorTestOp ops_create_many[] = {
529 { .type = QFILE_MONITOR_TEST_OP_CREATE,
530 .filesrc = "one.txt", },
531 { .type = QFILE_MONITOR_TEST_OP_CREATE,
532 .filesrc = "two.txt", },
533 { .type = QFILE_MONITOR_TEST_OP_CREATE,
534 .filesrc = "three.txt", }
537 static const QFileMonitorTestOp ops_rename_one[] = {
538 { .type = QFILE_MONITOR_TEST_OP_CREATE,
539 .filesrc = "one.txt", },
540 { .type = QFILE_MONITOR_TEST_OP_RENAME,
541 .filesrc = "one.txt", .filedst = "two.txt" }
544 static const QFileMonitorTestOp ops_rename_many[] = {
545 { .type = QFILE_MONITOR_TEST_OP_CREATE,
546 .filesrc = "one.txt", },
547 { .type = QFILE_MONITOR_TEST_OP_CREATE,
548 .filesrc = "two.txt", },
549 { .type = QFILE_MONITOR_TEST_OP_RENAME,
550 .filesrc = "one.txt", .filedst = "two.txt" }
553 static const QFileMonitorTestOp ops_append_one[] = {
554 { .type = QFILE_MONITOR_TEST_OP_CREATE,
555 .filesrc = "one.txt", },
556 { .type = QFILE_MONITOR_TEST_OP_APPEND,
557 .filesrc = "one.txt", },
560 static const QFileMonitorTestOp ops_trunc_one[] = {
561 { .type = QFILE_MONITOR_TEST_OP_CREATE,
562 .filesrc = "one.txt", },
563 { .type = QFILE_MONITOR_TEST_OP_TRUNC,
564 .filesrc = "one.txt", },
567 static const QFileMonitorTestOp ops_touch_one[] = {
568 { .type = QFILE_MONITOR_TEST_OP_CREATE,
569 .filesrc = "one.txt", },
570 { .type = QFILE_MONITOR_TEST_OP_TOUCH,
571 .filesrc = "one.txt", },
576 * No we define data sets for the combinatorial
577 * expansion of file watches and operation sets
579 #define PLAN_DATA(o, w) \
580 static const QFileMonitorTestPlan plan_ ## o ## _ ## w = { \
581 .nops = G_N_ELEMENTS(ops_ ##o), \
582 .ops = ops_ ##o, \
583 .nwatches = G_N_ELEMENTS(watches_ ##w), \
584 .watches = watches_ ## w, \
587 PLAN_DATA(create_one, any);
588 PLAN_DATA(create_one, one);
589 PLAN_DATA(create_one, two);
590 PLAN_DATA(create_one, many);
592 PLAN_DATA(delete_one, any);
593 PLAN_DATA(delete_one, one);
594 PLAN_DATA(delete_one, two);
595 PLAN_DATA(delete_one, many);
597 PLAN_DATA(create_many, any);
598 PLAN_DATA(create_many, one);
599 PLAN_DATA(create_many, two);
600 PLAN_DATA(create_many, many);
602 PLAN_DATA(rename_one, any);
603 PLAN_DATA(rename_one, one);
604 PLAN_DATA(rename_one, two);
605 PLAN_DATA(rename_one, many);
607 PLAN_DATA(rename_many, any);
608 PLAN_DATA(rename_many, one);
609 PLAN_DATA(rename_many, two);
610 PLAN_DATA(rename_many, many);
612 PLAN_DATA(append_one, any);
613 PLAN_DATA(append_one, one);
614 PLAN_DATA(append_one, two);
615 PLAN_DATA(append_one, many);
617 PLAN_DATA(trunc_one, any);
618 PLAN_DATA(trunc_one, one);
619 PLAN_DATA(trunc_one, two);
620 PLAN_DATA(trunc_one, many);
622 PLAN_DATA(touch_one, any);
623 PLAN_DATA(touch_one, one);
624 PLAN_DATA(touch_one, two);
625 PLAN_DATA(touch_one, many);
628 int main(int argc, char **argv)
630 g_test_init(&argc, &argv, NULL);
632 qemu_init_main_loop(&error_abort);
634 qemu_mutex_init(&evlock);
637 * Register test cases for the combinatorial
638 * expansion of file watches and operation sets
640 #define PLAN_REGISTER(o, w) \
641 g_test_add_data_func("/util/filemonitor/" # o "/" # w, \
642 &plan_ ## o ## _ ## w, test_file_monitor_events)
644 PLAN_REGISTER(create_one, any);
645 PLAN_REGISTER(create_one, one);
646 PLAN_REGISTER(create_one, two);
647 PLAN_REGISTER(create_one, many);
649 PLAN_REGISTER(delete_one, any);
650 PLAN_REGISTER(delete_one, one);
651 PLAN_REGISTER(delete_one, two);
652 PLAN_REGISTER(delete_one, many);
654 PLAN_REGISTER(create_many, any);
655 PLAN_REGISTER(create_many, one);
656 PLAN_REGISTER(create_many, two);
657 PLAN_REGISTER(create_many, many);
659 PLAN_REGISTER(rename_one, any);
660 PLAN_REGISTER(rename_one, one);
661 PLAN_REGISTER(rename_one, two);
662 PLAN_REGISTER(rename_one, many);
664 PLAN_REGISTER(rename_many, any);
665 PLAN_REGISTER(rename_many, one);
666 PLAN_REGISTER(rename_many, two);
667 PLAN_REGISTER(rename_many, many);
669 PLAN_REGISTER(append_one, any);
670 PLAN_REGISTER(append_one, one);
671 PLAN_REGISTER(append_one, two);
672 PLAN_REGISTER(append_one, many);
674 PLAN_REGISTER(trunc_one, any);
675 PLAN_REGISTER(trunc_one, one);
676 PLAN_REGISTER(trunc_one, two);
677 PLAN_REGISTER(trunc_one, many);
679 PLAN_REGISTER(touch_one, any);
680 PLAN_REGISTER(touch_one, one);
681 PLAN_REGISTER(touch_one, two);
682 PLAN_REGISTER(touch_one, many);
684 return g_test_run();