QFILE_MONITOR_TEST_OP_RENAME,
QFILE_MONITOR_TEST_OP_TOUCH,
QFILE_MONITOR_TEST_OP_UNLINK,
+ QFILE_MONITOR_TEST_OP_MKDIR,
+ QFILE_MONITOR_TEST_OP_RMDIR,
};
typedef struct {
int type;
const char *filesrc;
const char *filedst;
- int watchid;
+ int64_t *watchid;
int eventid;
+ /*
+ * Only valid with OP_EVENT - this event might be
+ * swapped with the next OP_EVENT
+ */
+ bool swapnext;
} QFileMonitorTestOp;
typedef struct {
- int id;
+ int64_t id;
QFileMonitorEvent event;
char *filename;
} QFileMonitorTestRecord;
* an ordered list of all events that it receives
*/
static void
-qemu_file_monitor_test_handler(int id,
+qemu_file_monitor_test_handler(int64_t id,
QFileMonitorEvent event,
const char *filename,
void *opaque)
QFileMonitorTestData *data = opaque;
QFileMonitorTestRecord *rec = g_new0(QFileMonitorTestRecord, 1);
+ if (debug) {
+ g_printerr("Queue event id %" PRIx64 " event %d file %s\n",
+ id, event, filename);
+ }
rec->id = id;
rec->event = event;
rec->filename = g_strdup(filename);
* to wait for the event to be queued for us.
*/
static QFileMonitorTestRecord *
-qemu_file_monitor_test_next_record(QFileMonitorTestData *data)
+qemu_file_monitor_test_next_record(QFileMonitorTestData *data,
+ QFileMonitorTestRecord *pushback)
{
GTimer *timer = g_timer_new();
QFileMonitorTestRecord *record = NULL;
}
if (data->records) {
record = data->records->data;
- tmp = data->records;
- data->records = g_list_remove_link(data->records, tmp);
- g_list_free(tmp);
+ if (pushback) {
+ data->records->data = pushback;
+ } else {
+ tmp = data->records;
+ data->records = g_list_remove_link(data->records, tmp);
+ g_list_free(tmp);
+ }
+ } else if (pushback) {
+ qemu_file_monitor_test_record_free(pushback);
}
qemu_mutex_unlock(&data->lock);
*/
static bool
qemu_file_monitor_test_expect(QFileMonitorTestData *data,
- int id,
+ int64_t id,
QFileMonitorEvent event,
- const char *filename)
+ const char *filename,
+ bool swapnext)
{
QFileMonitorTestRecord *rec;
bool ret = false;
- rec = qemu_file_monitor_test_next_record(data);
+ rec = qemu_file_monitor_test_next_record(data, NULL);
+ retry:
if (!rec) {
- g_printerr("Missing event watch id %d event %d file %s\n",
+ g_printerr("Missing event watch id %" PRIx64 " event %d file %s\n",
id, event, filename);
return false;
}
if (id != rec->id) {
- g_printerr("Expected watch id %d but got %d\n", id, rec->id);
+ if (swapnext) {
+ rec = qemu_file_monitor_test_next_record(data, rec);
+ swapnext = false;
+ goto retry;
+ }
+ g_printerr("Expected watch id %" PRIx64 " but got %" PRIx64 "\n",
+ id, rec->id);
goto cleanup;
}
static void
test_file_monitor_events(void)
{
+ int64_t watch0 = 0;
+ int64_t watch1 = 0;
+ int64_t watch2 = 0;
+ int64_t watch3 = 0;
+ int64_t watch4 = 0;
+ int64_t watch5 = 0;
QFileMonitorTestOp ops[] = {
{ .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
- .filesrc = NULL, .watchid = 0 },
+ .filesrc = NULL, .watchid = &watch0 },
{ .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
- .filesrc = "one.txt", .watchid = 1 },
+ .filesrc = "one.txt", .watchid = &watch1 },
{ .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
- .filesrc = "two.txt", .watchid = 2 },
+ .filesrc = "two.txt", .watchid = &watch2 },
{ .type = QFILE_MONITOR_TEST_OP_CREATE,
.filesrc = "one.txt", },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = 0,
+ .filesrc = "one.txt", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_CREATED },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = 1,
+ .filesrc = "one.txt", .watchid = &watch1,
.eventid = QFILE_MONITOR_EVENT_CREATED },
{ .type = QFILE_MONITOR_TEST_OP_CREATE,
.filesrc = "two.txt", },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = 0,
+ .filesrc = "two.txt", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_CREATED },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = 2,
+ .filesrc = "two.txt", .watchid = &watch2,
.eventid = QFILE_MONITOR_EVENT_CREATED },
{ .type = QFILE_MONITOR_TEST_OP_CREATE,
.filesrc = "three.txt", },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "three.txt", .watchid = 0,
+ .filesrc = "three.txt", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_CREATED },
{ .type = QFILE_MONITOR_TEST_OP_UNLINK,
.filesrc = "three.txt", },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "three.txt", .watchid = 0,
+ .filesrc = "three.txt", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_DELETED },
{ .type = QFILE_MONITOR_TEST_OP_RENAME,
.filesrc = "one.txt", .filedst = "two.txt" },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = 0,
+ .filesrc = "one.txt", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_DELETED },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = 1,
+ .filesrc = "one.txt", .watchid = &watch1,
.eventid = QFILE_MONITOR_EVENT_DELETED },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = 0,
+ .filesrc = "two.txt", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_CREATED },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = 2,
+ .filesrc = "two.txt", .watchid = &watch2,
.eventid = QFILE_MONITOR_EVENT_CREATED },
{ .type = QFILE_MONITOR_TEST_OP_APPEND,
.filesrc = "two.txt", },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = 0,
+ .filesrc = "two.txt", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_MODIFIED },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = 2,
+ .filesrc = "two.txt", .watchid = &watch2,
.eventid = QFILE_MONITOR_EVENT_MODIFIED },
{ .type = QFILE_MONITOR_TEST_OP_TOUCH,
.filesrc = "two.txt", },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = 0,
+ .filesrc = "two.txt", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_ATTRIBUTES },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = 2,
+ .filesrc = "two.txt", .watchid = &watch2,
.eventid = QFILE_MONITOR_EVENT_ATTRIBUTES },
{ .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
- .filesrc = "one.txt", .watchid = 1 },
+ .filesrc = "one.txt", .watchid = &watch1 },
{ .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
- .filesrc = "one.txt", .watchid = 3 },
+ .filesrc = "one.txt", .watchid = &watch3 },
{ .type = QFILE_MONITOR_TEST_OP_CREATE,
.filesrc = "one.txt", },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = 0,
+ .filesrc = "one.txt", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_CREATED },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = 3,
+ .filesrc = "one.txt", .watchid = &watch3,
.eventid = QFILE_MONITOR_EVENT_CREATED },
{ .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
- .filesrc = "one.txt", .watchid = 3 },
+ .filesrc = "one.txt", .watchid = &watch3 },
{ .type = QFILE_MONITOR_TEST_OP_UNLINK,
.filesrc = "one.txt", },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "one.txt", .watchid = 0,
+ .filesrc = "one.txt", .watchid = &watch0,
+ .eventid = QFILE_MONITOR_EVENT_DELETED },
+
+
+ { .type = QFILE_MONITOR_TEST_OP_MKDIR,
+ .filesrc = "fish", },
+ { .type = QFILE_MONITOR_TEST_OP_EVENT,
+ .filesrc = "fish", .watchid = &watch0,
+ .eventid = QFILE_MONITOR_EVENT_CREATED },
+
+
+ { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
+ .filesrc = "fish/", .watchid = &watch4 },
+ { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
+ .filesrc = "fish/one.txt", .watchid = &watch5 },
+ { .type = QFILE_MONITOR_TEST_OP_CREATE,
+ .filesrc = "fish/one.txt", },
+ { .type = QFILE_MONITOR_TEST_OP_EVENT,
+ .filesrc = "one.txt", .watchid = &watch4,
+ .eventid = QFILE_MONITOR_EVENT_CREATED },
+ { .type = QFILE_MONITOR_TEST_OP_EVENT,
+ .filesrc = "one.txt", .watchid = &watch5,
+ .eventid = QFILE_MONITOR_EVENT_CREATED },
+
+
+ { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
+ .filesrc = "fish/one.txt", .watchid = &watch5 },
+ { .type = QFILE_MONITOR_TEST_OP_RENAME,
+ .filesrc = "fish/one.txt", .filedst = "two.txt", },
+ { .type = QFILE_MONITOR_TEST_OP_EVENT,
+ .filesrc = "one.txt", .watchid = &watch4,
+ .eventid = QFILE_MONITOR_EVENT_DELETED },
+ { .type = QFILE_MONITOR_TEST_OP_EVENT,
+ .filesrc = "two.txt", .watchid = &watch0,
+ .eventid = QFILE_MONITOR_EVENT_CREATED },
+ { .type = QFILE_MONITOR_TEST_OP_EVENT,
+ .filesrc = "two.txt", .watchid = &watch2,
+ .eventid = QFILE_MONITOR_EVENT_CREATED },
+
+
+ { .type = QFILE_MONITOR_TEST_OP_RMDIR,
+ .filesrc = "fish", },
+ { .type = QFILE_MONITOR_TEST_OP_EVENT,
+ .filesrc = "", .watchid = &watch4,
+ .eventid = QFILE_MONITOR_EVENT_IGNORED,
+ .swapnext = true },
+ { .type = QFILE_MONITOR_TEST_OP_EVENT,
+ .filesrc = "fish", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_DELETED },
+ { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
+ .filesrc = "fish", .watchid = &watch4 },
{ .type = QFILE_MONITOR_TEST_OP_UNLINK,
.filesrc = "two.txt", },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = 0,
+ .filesrc = "two.txt", .watchid = &watch0,
.eventid = QFILE_MONITOR_EVENT_DELETED },
{ .type = QFILE_MONITOR_TEST_OP_EVENT,
- .filesrc = "two.txt", .watchid = 2,
+ .filesrc = "two.txt", .watchid = &watch2,
.eventid = QFILE_MONITOR_EVENT_DELETED },
{ .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
- .filesrc = "two.txt", .watchid = 2 },
+ .filesrc = "two.txt", .watchid = &watch2 },
{ .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
- .filesrc = NULL, .watchid = 0 },
+ .filesrc = NULL, .watchid = &watch0 },
};
Error *local_err = NULL;
GError *gerr = NULL;
char *pathsrc = NULL;
char *pathdst = NULL;
QFileMonitorTestData data;
+ GHashTable *ids = g_hash_table_new(g_int64_hash, g_int64_equal);
+ char *travis_arch;
qemu_mutex_init(&data.lock);
data.records = NULL;
+ /*
+ * This test does not work on Travis LXD containers since some
+ * syscalls are blocked in that environment.
+ */
+ travis_arch = getenv("TRAVIS_ARCH");
+ if (travis_arch && !g_str_equal(travis_arch, "x86_64")) {
+ g_test_skip("Test does not work on non-x86 Travis containers.");
+ return;
+ }
+
/*
* The file monitor needs the main loop running in
* order to receive events from inotify. We must
for (i = 0; i < G_N_ELEMENTS(ops); i++) {
const QFileMonitorTestOp *op = &(ops[i]);
int fd;
- int watchid;
struct utimbuf ubuf;
+ char *watchdir;
+ const char *watchfile;
pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc);
if (op->filedst) {
switch (op->type) {
case QFILE_MONITOR_TEST_OP_ADD_WATCH:
if (debug) {
- g_printerr("Add watch %s %s %d\n",
- dir, op->filesrc, op->watchid);
+ g_printerr("Add watch %s %s\n",
+ dir, op->filesrc);
}
- watchid =
+ if (op->filesrc && strchr(op->filesrc, '/')) {
+ watchdir = g_strdup_printf("%s/%s", dir, op->filesrc);
+ watchfile = strrchr(watchdir, '/');
+ *(char *)watchfile = '\0';
+ watchfile++;
+ if (*watchfile == '\0') {
+ watchfile = NULL;
+ }
+ } else {
+ watchdir = g_strdup(dir);
+ watchfile = op->filesrc;
+ }
+ *op->watchid =
qemu_file_monitor_add_watch(mon,
- dir,
- op->filesrc,
+ watchdir,
+ watchfile,
qemu_file_monitor_test_handler,
&data,
&local_err);
- if (watchid < 0) {
+ g_free(watchdir);
+ if (*op->watchid < 0) {
g_printerr("Unable to add watch %s",
error_get_pretty(local_err));
goto cleanup;
}
- if (watchid != op->watchid) {
- g_printerr("Unexpected watch ID %d, wanted %d\n",
- watchid, op->watchid);
+ if (debug) {
+ g_printerr("Watch ID %" PRIx64 "\n", *op->watchid);
+ }
+ if (g_hash_table_contains(ids, op->watchid)) {
+ g_printerr("Watch ID %" PRIx64 "already exists", *op->watchid);
goto cleanup;
}
+ g_hash_table_add(ids, op->watchid);
break;
case QFILE_MONITOR_TEST_OP_DEL_WATCH:
if (debug) {
- g_printerr("Del watch %s %d\n", dir, op->watchid);
+ g_printerr("Del watch %s %" PRIx64 "\n", dir, *op->watchid);
+ }
+ if (op->filesrc && strchr(op->filesrc, '/')) {
+ watchdir = g_strdup_printf("%s/%s", dir, op->filesrc);
+ watchfile = strrchr(watchdir, '/');
+ *(char *)watchfile = '\0';
+ } else {
+ watchdir = g_strdup(dir);
}
+ g_hash_table_remove(ids, op->watchid);
qemu_file_monitor_remove_watch(mon,
- dir,
- op->watchid);
+ watchdir,
+ *op->watchid);
+ g_free(watchdir);
break;
case QFILE_MONITOR_TEST_OP_EVENT:
if (debug) {
- g_printerr("Event id=%d event=%d file=%s\n",
- op->watchid, op->eventid, op->filesrc);
+ g_printerr("Event id=%" PRIx64 " event=%d file=%s\n",
+ *op->watchid, op->eventid, op->filesrc);
}
- if (!qemu_file_monitor_test_expect(
- &data, op->watchid, op->eventid, op->filesrc))
+ if (!qemu_file_monitor_test_expect(&data, *op->watchid,
+ op->eventid, op->filesrc,
+ op->swapnext))
goto cleanup;
break;
case QFILE_MONITOR_TEST_OP_CREATE:
}
break;
+ case QFILE_MONITOR_TEST_OP_MKDIR:
+ if (debug) {
+ g_printerr("Mkdir %s\n", pathsrc);
+ }
+ if (mkdir(pathsrc, 0700) < 0) {
+ g_printerr("Unable to mkdir %s: %s",
+ pathsrc, strerror(errno));
+ goto cleanup;
+ }
+ break;
+
+ case QFILE_MONITOR_TEST_OP_RMDIR:
+ if (debug) {
+ g_printerr("Rmdir %s\n", pathsrc);
+ }
+ if (rmdir(pathsrc) < 0) {
+ g_printerr("Unable to rmdir %s: %s",
+ pathsrc, strerror(errno));
+ goto cleanup;
+ }
+ break;
+
default:
g_assert_not_reached();
}
pathsrc = pathdst = NULL;
}
+ g_assert_cmpint(g_hash_table_size(ids), ==, 0);
+
err = 0;
cleanup:
const QFileMonitorTestOp *op = &(ops[i]);
char *path = g_strdup_printf("%s/%s",
dir, op->filesrc);
- unlink(path);
- g_free(path);
- if (op->filedst) {
- path = g_strdup_printf("%s/%s",
- dir, op->filedst);
+ if (op->type == QFILE_MONITOR_TEST_OP_MKDIR) {
+ rmdir(path);
+ g_free(path);
+ } else {
unlink(path);
g_free(path);
+ if (op->filedst) {
+ path = g_strdup_printf("%s/%s",
+ dir, op->filedst);
+ unlink(path);
+ g_free(path);
+ }
}
}
if (rmdir(dir) < 0) {
abort();
}
}
+ g_hash_table_unref(ids);
g_free(dir);
g_assert(err == 0);
}