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