]> git.proxmox.com Git - mirror_qemu.git/blame - tests/test-util-filemonitor.c
tests/acceptance: Add new test cases in linux_ssh_mips_malta.py
[mirror_qemu.git] / tests / test-util-filemonitor.c
CommitLineData
90e33dfe
DB
1/*
2 * Tests for util/filemonitor-*.c
3 *
4 * Copyright 2018 Red Hat, Inc.
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 */
20
21#include "qemu/osdep.h"
22#include "qemu/main-loop.h"
23#include "qapi/error.h"
24#include "qemu/filemonitor.h"
25
26#include <utime.h>
27
28enum {
b26c3f9c
DB
29 QFILE_MONITOR_TEST_OP_ADD_WATCH,
30 QFILE_MONITOR_TEST_OP_DEL_WATCH,
31 QFILE_MONITOR_TEST_OP_EVENT,
90e33dfe
DB
32 QFILE_MONITOR_TEST_OP_CREATE,
33 QFILE_MONITOR_TEST_OP_APPEND,
34 QFILE_MONITOR_TEST_OP_TRUNC,
35 QFILE_MONITOR_TEST_OP_RENAME,
36 QFILE_MONITOR_TEST_OP_TOUCH,
37 QFILE_MONITOR_TEST_OP_UNLINK,
ff3dc8fe
DB
38 QFILE_MONITOR_TEST_OP_MKDIR,
39 QFILE_MONITOR_TEST_OP_RMDIR,
90e33dfe
DB
40};
41
42typedef struct {
43 int type;
44 const char *filesrc;
45 const char *filedst;
b4682a63 46 int64_t *watchid;
b26c3f9c 47 int eventid;
bf9e0313
DB
48 /*
49 * Only valid with OP_EVENT - this event might be
50 * swapped with the next OP_EVENT
51 */
52 bool swapnext;
90e33dfe
DB
53} QFileMonitorTestOp;
54
90e33dfe 55typedef struct {
b4682a63 56 int64_t id;
90e33dfe
DB
57 QFileMonitorEvent event;
58 char *filename;
59} QFileMonitorTestRecord;
60
61
62typedef struct {
63 QemuMutex lock;
64 GList *records;
65} QFileMonitorTestData;
66
67static QemuMutex evlock;
68static bool evstopping;
69static bool evrunning;
b26c3f9c 70static bool debug;
90e33dfe
DB
71
72/*
73 * Main function for a background thread that is
74 * running the event loop during the test
75 */
76static void *
77qemu_file_monitor_test_event_loop(void *opaque G_GNUC_UNUSED)
78{
79 qemu_mutex_lock(&evlock);
80
81 while (!evstopping) {
82 qemu_mutex_unlock(&evlock);
83 main_loop_wait(true);
84 qemu_mutex_lock(&evlock);
85 }
86
87 evrunning = false;
88 qemu_mutex_unlock(&evlock);
89 return NULL;
90}
91
92
93/*
94 * File monitor event handler which simply maintains
95 * an ordered list of all events that it receives
96 */
97static void
b4682a63 98qemu_file_monitor_test_handler(int64_t id,
90e33dfe
DB
99 QFileMonitorEvent event,
100 const char *filename,
101 void *opaque)
102{
103 QFileMonitorTestData *data = opaque;
104 QFileMonitorTestRecord *rec = g_new0(QFileMonitorTestRecord, 1);
105
bf9e0313
DB
106 if (debug) {
107 g_printerr("Queue event id %" PRIx64 " event %d file %s\n",
108 id, event, filename);
109 }
90e33dfe
DB
110 rec->id = id;
111 rec->event = event;
112 rec->filename = g_strdup(filename);
113
114 qemu_mutex_lock(&data->lock);
115 data->records = g_list_append(data->records, rec);
116 qemu_mutex_unlock(&data->lock);
117}
118
119
120static void
121qemu_file_monitor_test_record_free(QFileMonitorTestRecord *rec)
122{
123 g_free(rec->filename);
124 g_free(rec);
125}
126
127
128/*
129 * Get the next event record that has been received by
130 * the file monitor event handler. Since events are
131 * emitted in the background thread running the event
132 * loop, we can't assume there is a record available
133 * immediately. Thus we will sleep for upto 5 seconds
134 * to wait for the event to be queued for us.
135 */
136static QFileMonitorTestRecord *
bf9e0313
DB
137qemu_file_monitor_test_next_record(QFileMonitorTestData *data,
138 QFileMonitorTestRecord *pushback)
90e33dfe
DB
139{
140 GTimer *timer = g_timer_new();
141 QFileMonitorTestRecord *record = NULL;
142 GList *tmp;
143
144 qemu_mutex_lock(&data->lock);
145 while (!data->records && g_timer_elapsed(timer, NULL) < 5) {
146 qemu_mutex_unlock(&data->lock);
147 usleep(10 * 1000);
148 qemu_mutex_lock(&data->lock);
149 }
150 if (data->records) {
151 record = data->records->data;
bf9e0313
DB
152 if (pushback) {
153 data->records->data = pushback;
154 } else {
155 tmp = data->records;
156 data->records = g_list_remove_link(data->records, tmp);
157 g_list_free(tmp);
158 }
159 } else if (pushback) {
160 qemu_file_monitor_test_record_free(pushback);
90e33dfe
DB
161 }
162 qemu_mutex_unlock(&data->lock);
163
164 g_timer_destroy(timer);
165 return record;
166}
167
168
169/*
170 * Check whether the event record we retrieved matches
171 * data we were expecting to see for the event
172 */
173static bool
174qemu_file_monitor_test_expect(QFileMonitorTestData *data,
b4682a63 175 int64_t id,
90e33dfe 176 QFileMonitorEvent event,
bf9e0313
DB
177 const char *filename,
178 bool swapnext)
90e33dfe
DB
179{
180 QFileMonitorTestRecord *rec;
181 bool ret = false;
182
bf9e0313 183 rec = qemu_file_monitor_test_next_record(data, NULL);
90e33dfe 184
bf9e0313 185 retry:
90e33dfe 186 if (!rec) {
b4682a63 187 g_printerr("Missing event watch id %" PRIx64 " event %d file %s\n",
90e33dfe
DB
188 id, event, filename);
189 return false;
190 }
191
192 if (id != rec->id) {
bf9e0313
DB
193 if (swapnext) {
194 rec = qemu_file_monitor_test_next_record(data, rec);
195 swapnext = false;
196 goto retry;
197 }
b4682a63
DB
198 g_printerr("Expected watch id %" PRIx64 " but got %" PRIx64 "\n",
199 id, rec->id);
90e33dfe
DB
200 goto cleanup;
201 }
202
203 if (event != rec->event) {
204 g_printerr("Expected event %d but got %d\n", event, rec->event);
205 goto cleanup;
206 }
207
208 if (!g_str_equal(filename, rec->filename)) {
209 g_printerr("Expected filename %s but got %s\n",
210 filename, rec->filename);
211 goto cleanup;
212 }
213
214 ret = true;
215
216 cleanup:
217 qemu_file_monitor_test_record_free(rec);
218 return ret;
219}
220
221
222static void
b26c3f9c 223test_file_monitor_events(void)
90e33dfe 224{
b4682a63
DB
225 int64_t watch0 = 0;
226 int64_t watch1 = 0;
227 int64_t watch2 = 0;
228 int64_t watch3 = 0;
229 int64_t watch4 = 0;
230 int64_t watch5 = 0;
b26c3f9c
DB
231 QFileMonitorTestOp ops[] = {
232 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 233 .filesrc = NULL, .watchid = &watch0 },
b26c3f9c 234 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 235 .filesrc = "one.txt", .watchid = &watch1 },
b26c3f9c 236 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 237 .filesrc = "two.txt", .watchid = &watch2 },
b26c3f9c
DB
238
239
240 { .type = QFILE_MONITOR_TEST_OP_CREATE,
241 .filesrc = "one.txt", },
242 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 243 .filesrc = "one.txt", .watchid = &watch0,
b26c3f9c
DB
244 .eventid = QFILE_MONITOR_EVENT_CREATED },
245 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 246 .filesrc = "one.txt", .watchid = &watch1,
b26c3f9c
DB
247 .eventid = QFILE_MONITOR_EVENT_CREATED },
248
249
250 { .type = QFILE_MONITOR_TEST_OP_CREATE,
251 .filesrc = "two.txt", },
252 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 253 .filesrc = "two.txt", .watchid = &watch0,
b26c3f9c
DB
254 .eventid = QFILE_MONITOR_EVENT_CREATED },
255 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 256 .filesrc = "two.txt", .watchid = &watch2,
b26c3f9c
DB
257 .eventid = QFILE_MONITOR_EVENT_CREATED },
258
259
260 { .type = QFILE_MONITOR_TEST_OP_CREATE,
261 .filesrc = "three.txt", },
262 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 263 .filesrc = "three.txt", .watchid = &watch0,
b26c3f9c
DB
264 .eventid = QFILE_MONITOR_EVENT_CREATED },
265
266
267 { .type = QFILE_MONITOR_TEST_OP_UNLINK,
268 .filesrc = "three.txt", },
269 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 270 .filesrc = "three.txt", .watchid = &watch0,
b26c3f9c
DB
271 .eventid = QFILE_MONITOR_EVENT_DELETED },
272
273
274 { .type = QFILE_MONITOR_TEST_OP_RENAME,
275 .filesrc = "one.txt", .filedst = "two.txt" },
276 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 277 .filesrc = "one.txt", .watchid = &watch0,
b26c3f9c
DB
278 .eventid = QFILE_MONITOR_EVENT_DELETED },
279 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 280 .filesrc = "one.txt", .watchid = &watch1,
b26c3f9c
DB
281 .eventid = QFILE_MONITOR_EVENT_DELETED },
282 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 283 .filesrc = "two.txt", .watchid = &watch0,
b26c3f9c
DB
284 .eventid = QFILE_MONITOR_EVENT_CREATED },
285 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 286 .filesrc = "two.txt", .watchid = &watch2,
b26c3f9c
DB
287 .eventid = QFILE_MONITOR_EVENT_CREATED },
288
289
290 { .type = QFILE_MONITOR_TEST_OP_APPEND,
291 .filesrc = "two.txt", },
292 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 293 .filesrc = "two.txt", .watchid = &watch0,
b26c3f9c
DB
294 .eventid = QFILE_MONITOR_EVENT_MODIFIED },
295 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 296 .filesrc = "two.txt", .watchid = &watch2,
b26c3f9c
DB
297 .eventid = QFILE_MONITOR_EVENT_MODIFIED },
298
299
300 { .type = QFILE_MONITOR_TEST_OP_TOUCH,
301 .filesrc = "two.txt", },
302 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 303 .filesrc = "two.txt", .watchid = &watch0,
b26c3f9c
DB
304 .eventid = QFILE_MONITOR_EVENT_ATTRIBUTES },
305 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 306 .filesrc = "two.txt", .watchid = &watch2,
b26c3f9c
DB
307 .eventid = QFILE_MONITOR_EVENT_ATTRIBUTES },
308
309
310 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 311 .filesrc = "one.txt", .watchid = &watch1 },
b26c3f9c 312 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 313 .filesrc = "one.txt", .watchid = &watch3 },
b26c3f9c
DB
314 { .type = QFILE_MONITOR_TEST_OP_CREATE,
315 .filesrc = "one.txt", },
316 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 317 .filesrc = "one.txt", .watchid = &watch0,
b26c3f9c
DB
318 .eventid = QFILE_MONITOR_EVENT_CREATED },
319 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 320 .filesrc = "one.txt", .watchid = &watch3,
b26c3f9c
DB
321 .eventid = QFILE_MONITOR_EVENT_CREATED },
322
323
324 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 325 .filesrc = "one.txt", .watchid = &watch3 },
b26c3f9c
DB
326 { .type = QFILE_MONITOR_TEST_OP_UNLINK,
327 .filesrc = "one.txt", },
328 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 329 .filesrc = "one.txt", .watchid = &watch0,
b26c3f9c
DB
330 .eventid = QFILE_MONITOR_EVENT_DELETED },
331
332
ff3dc8fe
DB
333 { .type = QFILE_MONITOR_TEST_OP_MKDIR,
334 .filesrc = "fish", },
335 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 336 .filesrc = "fish", .watchid = &watch0,
ff3dc8fe
DB
337 .eventid = QFILE_MONITOR_EVENT_CREATED },
338
339
340 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 341 .filesrc = "fish/", .watchid = &watch4 },
ff3dc8fe 342 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 343 .filesrc = "fish/one.txt", .watchid = &watch5 },
ff3dc8fe
DB
344 { .type = QFILE_MONITOR_TEST_OP_CREATE,
345 .filesrc = "fish/one.txt", },
346 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 347 .filesrc = "one.txt", .watchid = &watch4,
ff3dc8fe
DB
348 .eventid = QFILE_MONITOR_EVENT_CREATED },
349 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 350 .filesrc = "one.txt", .watchid = &watch5,
ff3dc8fe
DB
351 .eventid = QFILE_MONITOR_EVENT_CREATED },
352
353
354 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 355 .filesrc = "fish/one.txt", .watchid = &watch5 },
ff3dc8fe
DB
356 { .type = QFILE_MONITOR_TEST_OP_RENAME,
357 .filesrc = "fish/one.txt", .filedst = "two.txt", },
358 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 359 .filesrc = "one.txt", .watchid = &watch4,
ff3dc8fe
DB
360 .eventid = QFILE_MONITOR_EVENT_DELETED },
361 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 362 .filesrc = "two.txt", .watchid = &watch0,
ff3dc8fe
DB
363 .eventid = QFILE_MONITOR_EVENT_CREATED },
364 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 365 .filesrc = "two.txt", .watchid = &watch2,
ff3dc8fe
DB
366 .eventid = QFILE_MONITOR_EVENT_CREATED },
367
368
369 { .type = QFILE_MONITOR_TEST_OP_RMDIR,
370 .filesrc = "fish", },
371 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 372 .filesrc = "", .watchid = &watch4,
bf9e0313
DB
373 .eventid = QFILE_MONITOR_EVENT_IGNORED,
374 .swapnext = true },
ff3dc8fe 375 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 376 .filesrc = "fish", .watchid = &watch0,
ff3dc8fe
DB
377 .eventid = QFILE_MONITOR_EVENT_DELETED },
378 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 379 .filesrc = "fish", .watchid = &watch4 },
ff3dc8fe
DB
380
381
b26c3f9c
DB
382 { .type = QFILE_MONITOR_TEST_OP_UNLINK,
383 .filesrc = "two.txt", },
384 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 385 .filesrc = "two.txt", .watchid = &watch0,
b26c3f9c
DB
386 .eventid = QFILE_MONITOR_EVENT_DELETED },
387 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 388 .filesrc = "two.txt", .watchid = &watch2,
b26c3f9c
DB
389 .eventid = QFILE_MONITOR_EVENT_DELETED },
390
391
392 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 393 .filesrc = "two.txt", .watchid = &watch2 },
b26c3f9c 394 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 395 .filesrc = NULL, .watchid = &watch0 },
b26c3f9c 396 };
90e33dfe
DB
397 Error *local_err = NULL;
398 GError *gerr = NULL;
399 QFileMonitor *mon = qemu_file_monitor_new(&local_err);
400 QemuThread th;
401 GTimer *timer;
402 gchar *dir = NULL;
403 int err = -1;
b26c3f9c 404 gsize i;
90e33dfe
DB
405 char *pathsrc = NULL;
406 char *pathdst = NULL;
407 QFileMonitorTestData data;
b4682a63 408 GHashTable *ids = g_hash_table_new(g_int64_hash, g_int64_equal);
90e33dfe
DB
409
410 qemu_mutex_init(&data.lock);
411 data.records = NULL;
412
413 /*
414 * The file monitor needs the main loop running in
415 * order to receive events from inotify. We must
416 * thus spawn a background thread to run an event
417 * loop impl, while this thread triggers the
418 * actual file operations we're testing
419 */
420 evrunning = 1;
421 evstopping = 0;
422 qemu_thread_create(&th, "event-loop",
423 qemu_file_monitor_test_event_loop, NULL,
424 QEMU_THREAD_JOINABLE);
425
426 if (local_err) {
427 g_printerr("File monitoring not available: %s",
428 error_get_pretty(local_err));
429 error_free(local_err);
430 return;
431 }
432
433 dir = g_dir_make_tmp("test-util-filemonitor-XXXXXX",
434 &gerr);
435 if (!dir) {
436 g_printerr("Unable to create tmp dir %s",
437 gerr->message);
438 g_error_free(gerr);
439 abort();
440 }
441
442 /*
b26c3f9c
DB
443 * Run through the operation sequence validating events
444 * as we go
90e33dfe 445 */
b26c3f9c
DB
446 for (i = 0; i < G_N_ELEMENTS(ops); i++) {
447 const QFileMonitorTestOp *op = &(ops[i]);
90e33dfe
DB
448 int fd;
449 struct utimbuf ubuf;
ff3dc8fe
DB
450 char *watchdir;
451 const char *watchfile;
90e33dfe
DB
452
453 pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc);
454 if (op->filedst) {
455 pathdst = g_strdup_printf("%s/%s", dir, op->filedst);
456 }
457
458 switch (op->type) {
b26c3f9c
DB
459 case QFILE_MONITOR_TEST_OP_ADD_WATCH:
460 if (debug) {
b4682a63
DB
461 g_printerr("Add watch %s %s\n",
462 dir, op->filesrc);
b26c3f9c 463 }
ff3dc8fe
DB
464 if (op->filesrc && strchr(op->filesrc, '/')) {
465 watchdir = g_strdup_printf("%s/%s", dir, op->filesrc);
466 watchfile = strrchr(watchdir, '/');
467 *(char *)watchfile = '\0';
468 watchfile++;
469 if (*watchfile == '\0') {
470 watchfile = NULL;
471 }
472 } else {
473 watchdir = g_strdup(dir);
474 watchfile = op->filesrc;
475 }
b4682a63 476 *op->watchid =
b26c3f9c 477 qemu_file_monitor_add_watch(mon,
ff3dc8fe
DB
478 watchdir,
479 watchfile,
b26c3f9c
DB
480 qemu_file_monitor_test_handler,
481 &data,
482 &local_err);
ff3dc8fe 483 g_free(watchdir);
b4682a63 484 if (*op->watchid < 0) {
b26c3f9c
DB
485 g_printerr("Unable to add watch %s",
486 error_get_pretty(local_err));
487 goto cleanup;
488 }
b4682a63
DB
489 if (debug) {
490 g_printerr("Watch ID %" PRIx64 "\n", *op->watchid);
491 }
492 if (g_hash_table_contains(ids, op->watchid)) {
493 g_printerr("Watch ID %" PRIx64 "already exists", *op->watchid);
b26c3f9c
DB
494 goto cleanup;
495 }
b4682a63 496 g_hash_table_add(ids, op->watchid);
b26c3f9c
DB
497 break;
498 case QFILE_MONITOR_TEST_OP_DEL_WATCH:
499 if (debug) {
b4682a63 500 g_printerr("Del watch %s %" PRIx64 "\n", dir, *op->watchid);
b26c3f9c 501 }
ff3dc8fe
DB
502 if (op->filesrc && strchr(op->filesrc, '/')) {
503 watchdir = g_strdup_printf("%s/%s", dir, op->filesrc);
504 watchfile = strrchr(watchdir, '/');
505 *(char *)watchfile = '\0';
506 } else {
507 watchdir = g_strdup(dir);
508 }
b4682a63 509 g_hash_table_remove(ids, op->watchid);
b26c3f9c 510 qemu_file_monitor_remove_watch(mon,
ff3dc8fe 511 watchdir,
b4682a63 512 *op->watchid);
ff3dc8fe 513 g_free(watchdir);
b26c3f9c
DB
514 break;
515 case QFILE_MONITOR_TEST_OP_EVENT:
516 if (debug) {
b4682a63
DB
517 g_printerr("Event id=%" PRIx64 " event=%d file=%s\n",
518 *op->watchid, op->eventid, op->filesrc);
b26c3f9c 519 }
bf9e0313
DB
520 if (!qemu_file_monitor_test_expect(&data, *op->watchid,
521 op->eventid, op->filesrc,
522 op->swapnext))
b26c3f9c
DB
523 goto cleanup;
524 break;
90e33dfe 525 case QFILE_MONITOR_TEST_OP_CREATE:
b26c3f9c
DB
526 if (debug) {
527 g_printerr("Create %s\n", pathsrc);
528 }
90e33dfe
DB
529 fd = open(pathsrc, O_WRONLY | O_CREAT, 0700);
530 if (fd < 0) {
531 g_printerr("Unable to create %s: %s",
532 pathsrc, strerror(errno));
533 goto cleanup;
534 }
535 close(fd);
536 break;
537
538 case QFILE_MONITOR_TEST_OP_APPEND:
b26c3f9c
DB
539 if (debug) {
540 g_printerr("Append %s\n", pathsrc);
541 }
90e33dfe
DB
542 fd = open(pathsrc, O_WRONLY | O_APPEND, 0700);
543 if (fd < 0) {
544 g_printerr("Unable to open %s: %s",
545 pathsrc, strerror(errno));
546 goto cleanup;
547 }
548
549 if (write(fd, "Hello World", 10) != 10) {
550 g_printerr("Unable to write %s: %s",
551 pathsrc, strerror(errno));
552 close(fd);
553 goto cleanup;
554 }
555 close(fd);
556 break;
557
558 case QFILE_MONITOR_TEST_OP_TRUNC:
b26c3f9c
DB
559 if (debug) {
560 g_printerr("Truncate %s\n", pathsrc);
561 }
90e33dfe
DB
562 if (truncate(pathsrc, 4) < 0) {
563 g_printerr("Unable to truncate %s: %s",
564 pathsrc, strerror(errno));
565 goto cleanup;
566 }
567 break;
568
569 case QFILE_MONITOR_TEST_OP_RENAME:
b26c3f9c
DB
570 if (debug) {
571 g_printerr("Rename %s -> %s\n", pathsrc, pathdst);
572 }
90e33dfe
DB
573 if (rename(pathsrc, pathdst) < 0) {
574 g_printerr("Unable to rename %s to %s: %s",
575 pathsrc, pathdst, strerror(errno));
576 goto cleanup;
577 }
578 break;
579
580 case QFILE_MONITOR_TEST_OP_UNLINK:
b26c3f9c
DB
581 if (debug) {
582 g_printerr("Unlink %s\n", pathsrc);
583 }
90e33dfe
DB
584 if (unlink(pathsrc) < 0) {
585 g_printerr("Unable to unlink %s: %s",
586 pathsrc, strerror(errno));
587 goto cleanup;
588 }
589 break;
590
591 case QFILE_MONITOR_TEST_OP_TOUCH:
b26c3f9c
DB
592 if (debug) {
593 g_printerr("Touch %s\n", pathsrc);
594 }
90e33dfe
DB
595 ubuf.actime = 1024;
596 ubuf.modtime = 1025;
597 if (utime(pathsrc, &ubuf) < 0) {
598 g_printerr("Unable to touch %s: %s",
599 pathsrc, strerror(errno));
600 goto cleanup;
601 }
602 break;
603
ff3dc8fe
DB
604 case QFILE_MONITOR_TEST_OP_MKDIR:
605 if (debug) {
606 g_printerr("Mkdir %s\n", pathsrc);
607 }
608 if (mkdir(pathsrc, 0700) < 0) {
609 g_printerr("Unable to mkdir %s: %s",
610 pathsrc, strerror(errno));
611 goto cleanup;
612 }
613 break;
614
615 case QFILE_MONITOR_TEST_OP_RMDIR:
616 if (debug) {
617 g_printerr("Rmdir %s\n", pathsrc);
618 }
619 if (rmdir(pathsrc) < 0) {
620 g_printerr("Unable to rmdir %s: %s",
621 pathsrc, strerror(errno));
622 goto cleanup;
623 }
624 break;
625
90e33dfe
DB
626 default:
627 g_assert_not_reached();
628 }
629
630 g_free(pathsrc);
631 g_free(pathdst);
632 pathsrc = pathdst = NULL;
633 }
634
b4682a63
DB
635 g_assert_cmpint(g_hash_table_size(ids), ==, 0);
636
90e33dfe
DB
637 err = 0;
638
639 cleanup:
640 g_free(pathsrc);
641 g_free(pathdst);
642
643 qemu_mutex_lock(&evlock);
644 evstopping = 1;
645 timer = g_timer_new();
646 while (evrunning && g_timer_elapsed(timer, NULL) < 5) {
647 qemu_mutex_unlock(&evlock);
648 usleep(10 * 1000);
649 qemu_mutex_lock(&evlock);
650 }
651 qemu_mutex_unlock(&evlock);
652
653 if (g_timer_elapsed(timer, NULL) >= 5) {
654 g_printerr("Event loop failed to quit after 5 seconds\n");
655 }
656 g_timer_destroy(timer);
657
90e33dfe
DB
658 qemu_file_monitor_free(mon);
659 g_list_foreach(data.records,
660 (GFunc)qemu_file_monitor_test_record_free, NULL);
661 g_list_free(data.records);
662 qemu_mutex_destroy(&data.lock);
663 if (dir) {
b26c3f9c
DB
664 for (i = 0; i < G_N_ELEMENTS(ops); i++) {
665 const QFileMonitorTestOp *op = &(ops[i]);
666 char *path = g_strdup_printf("%s/%s",
667 dir, op->filesrc);
ff3dc8fe
DB
668 if (op->type == QFILE_MONITOR_TEST_OP_MKDIR) {
669 rmdir(path);
670 g_free(path);
671 } else {
b26c3f9c
DB
672 unlink(path);
673 g_free(path);
ff3dc8fe
DB
674 if (op->filedst) {
675 path = g_strdup_printf("%s/%s",
676 dir, op->filedst);
677 unlink(path);
678 g_free(path);
679 }
b26c3f9c
DB
680 }
681 }
682 if (rmdir(dir) < 0) {
683 g_printerr("Failed to remove %s: %s\n",
684 dir, strerror(errno));
685 abort();
686 }
90e33dfe 687 }
b4682a63 688 g_hash_table_unref(ids);
90e33dfe
DB
689 g_free(dir);
690 g_assert(err == 0);
691}
692
693
90e33dfe
DB
694int main(int argc, char **argv)
695{
696 g_test_init(&argc, &argv, NULL);
697
698 qemu_init_main_loop(&error_abort);
699
700 qemu_mutex_init(&evlock);
701
b26c3f9c
DB
702 debug = getenv("FILEMONITOR_DEBUG") != NULL;
703 g_test_add_func("/util/filemonitor", test_file_monitor_events);
90e33dfe
DB
704
705 return g_test_run();
706}