eio: add OSX implementation of eio_monitor based on FSEvent

this patch adds an implementation of eio_monitor based on FSEvent
for OSX. This implentation has some limitations compared to inotify
implementation. Folowing events are not detected:
  - EIO_MONITOR_FILE_CLOSED
  - EIO_MONITOR_SELF_RENAME
  - EIO_MONITOR_SELF_DELETED

It should be noted that some events that happend before the call
to eio_monitor_add can be catched. This is why sleep timers have
been added in the test suite.

Tests have been added to check uncovered scenarios.

some things might still be improved:
  - self_deleted events for files might be handled by checking the
    file_name manually

  - self_deleted events for directories might be handled by setting
    kFSEventStreamCreateFlagWatchRoot. I've noticed by doing so that
	a lot more unwanted event are raised

Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
This commit is contained in:
pierre lamot 2015-02-26 14:37:45 +01:00 committed by Cedric BAIL
parent ae4389a7bd
commit d958afd9fd
6 changed files with 784 additions and 109 deletions

View File

@ -417,19 +417,8 @@ sys/mman.h \
netinet/in.h \
])
have_inotify="${ac_cv_header_sys_inotify_h}"
AM_CONDITIONAL([HAVE_INOTIFY], [test "x${have_inotify}" = "xyes"])
have_notify_win32="${have_win32}"
AC_DEFINE_IF([HAVE_NOTIFY_WIN32],
[test "x${have_notify_win32}" = "xyes"], [1],
[File monitoring with Windows notification])
AM_CONDITIONAL([HAVE_NOTIFY_WIN32], [test "x${have_notify_win32}" = "xyes"])
EFL_CHECK_PATH_MAX
#### Checks for types
# wchar_t
@ -1329,11 +1318,11 @@ AC_ARG_ENABLE([cocoa],
],
[want_cocoa="no"])
if test "${want_cocoa}" = "yes"; then
#test cocoa requirements (objc and Cocoa/Cocoa.h)
cocoa_ldflags=""
have_cocoa="no"
m4_ifdef([AC_PROG_OBJC],
if test "${want_cocoa}" = "yes"; then
#test cocoa requirements (objc and Cocoa/Cocoa.h)
cocoa_ldflags=""
have_cocoa="no"
m4_ifdef([AC_PROG_OBJC],
[
if test "x${have_gnu_objc}" = "xyes" ; then
AC_LANG_PUSH([Objective C])
@ -1368,6 +1357,38 @@ window = [[NSWindow alloc]
fi
AC_SUBST(cocoa_ldflags)
if test "x${want_cocoa}" = "xyes"; then
#test cocoa requirements (objc and Cocoa/Cocoa.h)
cocoa_coreservices_ldflags=""
have_cocoa_coreservices="no"
m4_ifdef([AC_PROG_OBJC],
[
if test "x${have_gnu_objc}" = "xyes" ; then
AC_LANG_PUSH([Objective C])
LIBS_save="$LIBS"
LIBS="$LIBS -framework CoreServices"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[
#include <CoreServices/CoreServices.h>
]],
[[
//test function here
]])],
[
have_cocoa_coreservices="yes"
cocoa_coreservices_ldflags="-framework CoreServices"
],
[have_cocoa_coreservices="no"])
LIBS="$LIBS_save"
AC_MSG_CHECKING([whether Cocoa CoreServices framework is supported])
AC_MSG_RESULT([${have_cocoa_coreservices}])
AC_LANG_POP([Objective C])
fi
])
fi
AC_SUBST(cocoa_coreservices_ldflags)
# Drm
AC_ARG_ENABLE([drm],
[AS_HELP_STRING([--enable-drm],[enable drm engine. @<:@default=disabled@:>@])],
@ -3969,6 +3990,20 @@ EFL_ADD_LIBS([EIO], [-lm])
### Checks for linker characteristics
### Checks for library functions
have_inotify="${ac_cv_header_sys_inotify_h}"
AM_CONDITIONAL([HAVE_INOTIFY], [test "x${have_inotify}" = "xyes"])
have_notify_win32="${have_win32}"
AC_DEFINE_IF([HAVE_NOTIFY_WIN32],
[test "x${have_notify_win32}" = "xyes"], [1],
[File monitoring with Windows notification])
AM_CONDITIONAL([HAVE_NOTIFY_WIN32], [test "x${have_notify_win32}" = "xyes"])
AC_DEFINE_IF([HAVE_NOTIFY_COCOA],
[test "x${have_darwin}" = "xyes"], [1],
[File monitoring with fsevent notification])
AM_CONDITIONAL([HAVE_NOTIFY_COCOA], [test "x${have_darwin}" = "xyes"])
EFL_LIB_END([Eio])
dnl TODO: remove these ifdefs from code!

View File

@ -23,6 +23,10 @@ lib_eio_libeio_la_SOURCES += lib/eio/eio_monitor_inotify.c
else
if HAVE_NOTIFY_WIN32
lib_eio_libeio_la_SOURCES += lib/eio/eio_monitor_win32.c
else
if HAVE_NOTIFY_COCOA
lib_eio_libeio_la_SOURCES += lib/eio/eio_monitor_cocoa.c
endif
endif
endif
@ -30,6 +34,9 @@ lib_eio_libeio_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @EIO_CFLAGS@
lib_eio_libeio_la_LIBADD = @EIO_LIBS@
lib_eio_libeio_la_DEPENDENCIES = @EIO_INTERNAL_LIBS@
lib_eio_libeio_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
if HAVE_NOTIFY_COCOA
lib_eio_libeio_la_LDFLAGS += -framework CoreServices
endif
if EFL_ENABLE_TESTS

View File

@ -1219,13 +1219,13 @@ EAPI Eio_File *eio_eet_write_cipher(Eet_File *ef,
EAPI extern int EIO_MONITOR_FILE_CREATED; /**< A new file was created in a watched directory */
EAPI extern int EIO_MONITOR_FILE_DELETED; /**< A watched file was deleted, or a file in a watched directory was deleted */
EAPI extern int EIO_MONITOR_FILE_MODIFIED; /**< A file was modified in a watched directory */
EAPI extern int EIO_MONITOR_FILE_CLOSED; /**< A file was closed in a watched directory. This event is never sent on Windows */
EAPI extern int EIO_MONITOR_FILE_CLOSED; /**< A file was closed in a watched directory. This event is never sent on Windows and OSX */
EAPI extern int EIO_MONITOR_DIRECTORY_CREATED; /**< A new directory was created in a watched directory */
EAPI extern int EIO_MONITOR_DIRECTORY_DELETED; /**< A directory has been deleted: this can be either a watched directory or one of its subdirectories */
EAPI extern int EIO_MONITOR_DIRECTORY_MODIFIED; /**< A directory has been modified in a watched directory */
EAPI extern int EIO_MONITOR_DIRECTORY_CLOSED; /**< A directory has been closed in a watched directory. This event is never sent on Windows */
EAPI extern int EIO_MONITOR_SELF_RENAME; /**< The monitored path has been renamed, an error could happen just after if the renamed path doesn't exist */
EAPI extern int EIO_MONITOR_SELF_DELETED; /**< The monitored path has been removed */
EAPI extern int EIO_MONITOR_DIRECTORY_CLOSED; /**< A directory has been closed in a watched directory. This event is never sent on Windows and OSX */
EAPI extern int EIO_MONITOR_SELF_RENAME; /**< The monitored path has been renamed, an error could happen just after if the renamed path doesn't exist. This event is never sent on OSX */
EAPI extern int EIO_MONITOR_SELF_DELETED; /**< The monitored path has been removed. This event is never sent on OSX */
EAPI extern int EIO_MONITOR_ERROR; /**< During operation the monitor failed and will no longer work. eio_monitor_del must be called on it. */
typedef struct _Eio_Monitor Eio_Monitor;

View File

@ -0,0 +1,405 @@
/* EIO - EFL data type library
* Copyright (C) 2015 Enlightenment Developers:
* Pierre Lamot <pierre.lamot@openwide.fr>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
*/
#include "eio_private.h"
#include "Eio.h"
#import <CoreServices/CoreServices.h>
static CFTimeInterval _latency = 0.1;
/*============================================================================*
* Local *
*============================================================================*/
/**
* @cond LOCAL
*/
struct _Eio_Monitor_Backend
{
Eio_Monitor *parent;
///the monitored path
char *mon_path;
///the actual file path
char *real_path;
};
typedef struct _FSEvent_Info FSEvent_Info;
struct _FSEvent_Info {
char *path;
FSEventStreamEventFlags flags;
};
typedef struct _Eio_FSEvent_Table Eio_FSEvent_Table;
struct _Eio_FSEvent_Table
{
int mask;
int *ev_file_code;
int *ev_dir_code;
};
#define EIO_FSEVENT_LINE(FSe, Ef, Ed) \
{ kFSEventStreamEventFlag##FSe, &EIO_MONITOR_##Ef, &EIO_MONITOR_##Ed }
static const Eio_FSEvent_Table match[] = {
EIO_FSEVENT_LINE(ItemChangeOwner, FILE_MODIFIED, DIRECTORY_MODIFIED),
EIO_FSEVENT_LINE(ItemInodeMetaMod, FILE_MODIFIED, DIRECTORY_MODIFIED),
EIO_FSEVENT_LINE(ItemXattrMod, FILE_MODIFIED, DIRECTORY_MODIFIED),
EIO_FSEVENT_LINE(ItemModified, FILE_MODIFIED, DIRECTORY_MODIFIED),
EIO_FSEVENT_LINE(ItemRemoved, FILE_DELETED, DIRECTORY_DELETED),
EIO_FSEVENT_LINE(ItemCreated, FILE_CREATED, DIRECTORY_CREATED),
EIO_FSEVENT_LINE(RootChanged, SELF_DELETED, SELF_DELETED)
};
static FSEventStreamRef _stream = NULL;
static Eina_Hash *_fsevent_monitors = NULL;
static CFMutableArrayRef _paths_to_watch = NULL;
static dispatch_queue_t _dispatch_queue;
static Eina_Bool
_handle_fsevent_with_monitor(const Eina_Hash *hash EINA_UNUSED,
const void *key EINA_UNUSED,
void *data,
void *fdata)
{
FSEvent_Info *event_info = (FSEvent_Info*)fdata;
Eio_Monitor_Backend *backend = (Eio_Monitor_Backend*)data;
FSEventStreamEventFlags flags = event_info->flags;
unsigned int i;
Eina_Bool is_dir;
unsigned int length, tmp_length;
char *tmp = NULL;
if (backend->parent->delete_me)
return 1;
if (!eina_str_has_prefix(event_info->path, backend->real_path))
{
return 1;
}
length = strlen(event_info->path) - strlen(backend->real_path);
if (length == 0)
{
tmp = strdup(backend->parent->path);
}
else
{
tmp_length =
eina_stringshare_strlen(backend->parent->path) + length + 2;
tmp = malloc(sizeof(char) * tmp_length);
snprintf(tmp, tmp_length, "%s/%s",
backend->parent->path,
&(event_info->path[strlen(backend->real_path) + 1]));
}
is_dir = !!(flags & kFSEventStreamEventFlagItemIsDir);
for (i = 0; i < sizeof (match) / sizeof (Eio_FSEvent_Table); ++i)
if (match[i].mask & flags)
{
DBG("send event from %s with event %X\n", event_info->path, flags);
_eio_monitor_send(backend->parent,
tmp,
is_dir ? *match[i].ev_dir_code : *match[i].ev_file_code);
}
free(tmp);
//we have found the right event, no need to continue
return 0;
}
static void
_main_loop_send_event(void *data)
{
FSEvent_Info *info = (FSEvent_Info*)data;
if (!_stream)
{
//this can happen, when eio_shutdown is called
goto cleanup;
}
if ((info->flags & kFSEventStreamEventFlagKernelDropped) != 0)
{
_eio_monitor_send(NULL, "", EIO_MONITOR_ERROR);
goto cleanup;
}
eina_hash_foreach(_fsevent_monitors,
_handle_fsevent_with_monitor,
info);
cleanup:
free(info->path);
free(info);
}
static void
_eio_fsevent_cb(ConstFSEventStreamRef stream_ref EINA_UNUSED,
void *ctx EINA_UNUSED,
size_t count,
void *event_paths,
const FSEventStreamEventFlags event_flags[],
const FSEventStreamEventId event_ids[] EINA_UNUSED
)
{
size_t i;
FSEvent_Info *event_info;
for (i = 0; i < count; i++)
{
event_info = malloc(sizeof(FSEvent_Info));
event_info->path = strdup(((char**)event_paths)[i]);
event_info->flags = event_flags[i];
ecore_main_loop_thread_safe_call_async(_main_loop_send_event,
event_info);
}
}
static void
_eio_fsevent_del(void *data)
{
Eio_Monitor_Backend *backend = (Eio_Monitor_Backend *)data;
free(backend);
}
static void
_eio_get_monitor_path(const char *path, char **monpath, char **fullpath)
{
char realPath[PATH_MAX];
char *realPathOk;
char *dname = NULL;
char *fname = NULL;
struct stat sb;
realPathOk = realpath(path, realPath);
if (realPathOk == NULL)
{
dname = dirname((char*)path);
if (strcmp(dname, ".") == 0)
{
realPathOk = realpath("./", realPath);
}
else
{
realPathOk = realpath(dname, realPath);
}
if (realPathOk == NULL)
return;
}
if (stat(realPath, &sb) < 0)
{
return;
}
if (S_ISDIR(sb.st_mode))
{
if (fullpath)
*fullpath = strdup(realPath);
if (monpath)
*monpath = strdup(realPath);
}
else
{
//not a directory, monitor parent
if (fullpath)
*fullpath = strdup(realPath);
dname = dirname(realPath);
if (monpath)
*monpath = strdup(dname);
}
}
/**
* @endcond
*/
/*============================================================================*
* Global *
*============================================================================*/
/**
* @cond LOCAL
*/
/**
* @endcond
*/
void eio_monitor_backend_init(void)
{
_dispatch_queue = dispatch_queue_create("org.elf.fseventqueue", NULL);
_fsevent_monitors = eina_hash_string_small_new(_eio_fsevent_del);
_paths_to_watch = CFArrayCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeArrayCallBacks);
}
void eio_monitor_backend_shutdown(void)
{
if (_stream)
{
FSEventStreamStop(_stream);
FSEventStreamInvalidate(_stream);
FSEventStreamRelease(_stream);
_stream = NULL;
}
dispatch_release(_dispatch_queue);
eina_hash_free(_fsevent_monitors);
CFRelease(_paths_to_watch);
}
void eio_monitor_backend_add(Eio_Monitor *monitor)
{
Eio_Monitor_Backend *backend;
FSEventStreamEventId eventid;
CFStringRef path = NULL;
//the path we should monitor
char *monitor_path = NULL;
//the real file path
char *real_path = NULL;
_eio_get_monitor_path(monitor->path, &monitor_path, &real_path);
backend = calloc(1, sizeof (Eio_Monitor_Backend));
if (!backend)
{
free(monitor_path);
eio_monitor_fallback_add(monitor);
return;
}
path = CFStringCreateWithCString(NULL,
monitor_path,
kCFStringEncodingUTF8);
CFArrayAppendValue(_paths_to_watch, path);
if (_stream)
{
eventid = FSEventStreamGetLatestEventId(_stream);
FSEventStreamRelease(_stream);
_stream = NULL;
}
else
{
eventid = kFSEventStreamEventIdSinceNow;
}
_stream = FSEventStreamCreate(NULL,
_eio_fsevent_cb,
NULL,
_paths_to_watch,
eventid,
_latency,
kFSEventStreamCreateFlagFileEvents
| kFSEventStreamCreateFlagNoDefer
);
if (!_stream)
{
eio_monitor_fallback_add(monitor);
return;
}
backend->parent = monitor;
backend->mon_path = monitor_path;
backend->real_path = real_path;
monitor->backend = backend;
eina_hash_direct_add(_fsevent_monitors, monitor->path, backend);
FSEventStreamSetDispatchQueue(_stream, _dispatch_queue);
FSEventStreamStart(_stream);
}
void eio_monitor_backend_del(Eio_Monitor *monitor)
{
Eio_Monitor_Backend *backend;
CFStringRef path = NULL;
FSEventStreamEventId eventid;
char *monitor_path;
if (!_stream)
{
eio_monitor_fallback_del(monitor);
return;
}
_eio_get_monitor_path(monitor->path, &monitor_path, NULL);
eventid = FSEventStreamGetLatestEventId(_stream);
FSEventStreamRelease(_stream);
_stream = NULL;
path = CFStringCreateWithCString(NULL,
monitor_path,
kCFStringEncodingUTF8);
CFIndex idx =
CFArrayGetFirstIndexOfValue(_paths_to_watch,
CFRangeMake(0,
CFArrayGetCount(_paths_to_watch)
),
path);
if (idx != -1)
{
CFArrayRemoveValueAtIndex(_paths_to_watch, idx);
}
_stream = FSEventStreamCreate(NULL,
_eio_fsevent_cb,
NULL,
_paths_to_watch,
eventid,
_latency,
kFSEventStreamCreateFlagFileEvents
| kFSEventStreamCreateFlagNoDefer
);
backend = monitor->backend;
monitor->backend = NULL;
if (!backend) return;
eina_hash_del(_fsevent_monitors, monitor->path, backend);
}
/*============================================================================*
* API *
*============================================================================*/

View File

@ -270,7 +270,7 @@ _eio_monitor_fallback_timer_cb(void *data)
* @cond LOCAL
*/
#if !defined HAVE_SYS_INOTIFY_H && !defined HAVE_NOTIFY_WIN32
#if !defined HAVE_SYS_INOTIFY_H && !defined HAVE_NOTIFY_WIN32 && !defined HAVE_NOTIFY_COCOA
void eio_monitor_backend_init(void)
{
}

View File

@ -17,9 +17,9 @@
#define TEST_TIMEOUT_SEC 10
#define TEST_OPERATION_DELAY 0.5
static Ecore_Timer * test_timeout_timer;
static Ecore_Timer *test_timeout_timer;
static Eina_Bool _test_timeout_cb(void* data EINA_UNUSED)
static Eina_Bool _test_timeout_cb(void *data EINA_UNUSED)
{
ck_abort_msg("test timeout");
ecore_main_loop_quit();
@ -35,16 +35,26 @@ static void _cancel_timeout()
}
}
static Eina_Bool _test_timeout_expected(void *data EINA_UNUSED)
{
if (test_timeout_timer != NULL)
{
_cancel_timeout();
}
ecore_main_loop_quit();
return ECORE_CALLBACK_CANCEL;
}
///////////////// file and directory operations
typedef struct {
const char* src;
const char* dst;
const char *src;
const char *dst;
} RenameOperation;
static Eina_Bool _delete_directory(void* data)
static Eina_Bool _delete_directory(void *data)
{
const char* dirname = (const char*)data;
const char *dirname = (const char*)data;
if (ecore_file_is_dir(dirname))
{
ecore_file_recursive_rm(dirname);
@ -52,40 +62,40 @@ static Eina_Bool _delete_directory(void* data)
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool _create_directory(void* data)
static Eina_Bool _create_directory(void *data)
{
const char* dirname = (const char*)data;
const char *dirname = (const char*)data;
ecore_file_mkpath(dirname);
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool _create_file(void* data)
static Eina_Bool _create_file(void *data)
{
FILE* fd = fopen((const char*)data, "w+");
FILE *fd = fopen((const char*)data, "w+");
ck_assert_ptr_ne(fd, NULL);
fprintf(fd, "test test");
fclose(fd);
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool _delete_file(void* data)
static Eina_Bool _delete_file(void *data)
{
Eina_Bool file_removed = ecore_file_remove((const char*)data);
ck_assert(file_removed);
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool _modify_file(void* data)
static Eina_Bool _modify_file(void *data)
{
FILE* fd = fopen((const char*)data, "a");
FILE *fd = fopen((const char*)data, "a");
ck_assert_ptr_ne(fd, NULL);
fprintf(fd, "appened");
fclose(fd);
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool _modify_attrib_file(void* data)
static Eina_Bool _modify_attrib_file(void *data)
{
int ret = chmod((const char*)data, 0666);
ck_assert_int_eq(ret, 0);
@ -94,16 +104,17 @@ static Eina_Bool _modify_attrib_file(void* data)
/////// helper functions
static void _check_event_path(void* data, void* event)
static Eina_Bool _check_event_path(void *data, void *event)
{
const char* expected_path = ecore_file_realpath((const char*)data);
const char* actual_path = ecore_file_realpath(((Eio_Monitor_Event*)event)->filename);
ck_assert_str_eq(actual_path, expected_path);
const char *expected_path = (const char*)data;
const char *actual_path = ((Eio_Monitor_Event*)event)->filename;
ck_assert_str_eq((const char*)data, ((Eio_Monitor_Event*)event)->filename);
return EINA_TRUE;
}
static Eina_Tmpstr* _common_init()
static Eina_Tmpstr *_common_init()
{
Eina_Tmpstr* dirname;
Eina_Tmpstr *dirname;
fail_if(eio_init() != 1);
ecore_file_init();
@ -114,7 +125,7 @@ static Eina_Tmpstr* _common_init()
return dirname;
}
static void _common_shutdown(Eina_Tmpstr* dirname)
static void _common_shutdown(Eina_Tmpstr *dirname)
{
_delete_directory((void*)dirname);
ecore_file_shutdown();
@ -124,21 +135,26 @@ static void _common_shutdown(Eina_Tmpstr* dirname)
/////// tests monitoring a directory
static void _file_created_cb(void* data, int type, void* event)
static void _file_created_cb(void *data, int type, void *event)
{
ck_assert_int_eq(type, (int)EIO_MONITOR_FILE_CREATED);
_check_event_path(data, event);
_cancel_timeout();
ecore_main_loop_quit();
if (_check_event_path(data, event))
{
_cancel_timeout();
ecore_main_loop_quit();
}
}
START_TEST(eio_test_monitor_directory_file_created_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Stringshare* filename;
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
filename = eina_stringshare_printf("%s/filecreated", dirname);
filename = eina_stringshare_printf("%s/eio_test_monitor_directory_file_created_notify", dirname);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
eio_monitor_add(dirname);
@ -152,22 +168,27 @@ START_TEST(eio_test_monitor_directory_file_created_notify)
}
END_TEST
static void _file_deleted_cb(void* data, int type, void* event)
static void _file_deleted_cb(void *data, int type, void *event)
{
ck_assert_int_eq(type, (int)EIO_MONITOR_FILE_DELETED);
_check_event_path(data, event);
_cancel_timeout();
ecore_main_loop_quit();
if (_check_event_path(data, event))
{
_cancel_timeout();
ecore_main_loop_quit();
}
}
START_TEST(eio_test_monitor_directory_file_deleted_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Stringshare* filename;
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
filename = eina_stringshare_printf("%s/filecreated", dirname);
filename = eina_stringshare_printf("%s/eio_test_monitor_directory_file_deleted_notify", dirname);
_create_file((void*)filename);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
eio_monitor_add(dirname);
ecore_event_handler_add(EIO_MONITOR_FILE_DELETED, (Ecore_Event_Handler_Cb)_file_deleted_cb, filename);
@ -180,22 +201,27 @@ START_TEST(eio_test_monitor_directory_file_deleted_notify)
}
END_TEST
static void _file_modified_cb(void* data, int type, void* event)
static void _file_modified_cb(void *data, int type, void *event)
{
ck_assert_int_eq(type, (int)EIO_MONITOR_FILE_MODIFIED);
_check_event_path(data, event);
_cancel_timeout();
ecore_main_loop_quit();
if(_check_event_path(data, event))
{
_cancel_timeout();
ecore_main_loop_quit();
}
}
START_TEST(eio_test_monitor_directory_file_modified_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Stringshare* filename;
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
filename = eina_stringshare_printf("%s/filecreated", dirname);
filename = eina_stringshare_printf("%s/eio_test_monitor_directory_file_modified_notify", dirname);
_create_file((void*)filename);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
eio_monitor_add(dirname);
ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, (Ecore_Event_Handler_Cb)_file_modified_cb, filename);
@ -209,22 +235,27 @@ START_TEST(eio_test_monitor_directory_file_modified_notify)
}
END_TEST
static void _file_closed_cb(void* data, int type, void* event)
static void _file_closed_cb(void *data, int type, void *event)
{
ck_assert_int_eq(type, (int)EIO_MONITOR_FILE_CLOSED);
_check_event_path(data, event);
_cancel_timeout();
ecore_main_loop_quit();
if (_check_event_path(data, event))
{
_cancel_timeout();
ecore_main_loop_quit();
}
}
START_TEST(eio_test_monitor_directory_file_closed_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Stringshare* filename;
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
filename = eina_stringshare_printf("%s/filecreated", dirname);
filename = eina_stringshare_printf("%s/eio_test_monitor_directory_file_closed_notify", dirname);
_create_file((void*)filename);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
eio_monitor_add(dirname);
ecore_event_handler_add(EIO_MONITOR_FILE_CLOSED, (Ecore_Event_Handler_Cb)_file_closed_cb, filename);
@ -236,20 +267,25 @@ START_TEST(eio_test_monitor_directory_file_closed_notify)
}
END_TEST
static void _directory_created_cb(void* data, int type, void* event)
static void _directory_created_cb(void *data, int type, void *event)
{
ck_assert_int_eq(type, (int)EIO_MONITOR_DIRECTORY_CREATED);
_check_event_path(data, event);
_cancel_timeout();
ecore_main_loop_quit();
if (_check_event_path(data, event))
{
_cancel_timeout();
ecore_main_loop_quit();
}
}
START_TEST(eio_test_monitor_directory_directory_created_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Stringshare* filename;
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
filename = eina_stringshare_printf("%s/dircreated", dirname);
filename = eina_stringshare_printf("%s/eio_test_monitor_directory_directory_created_notify", dirname);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
eio_monitor_add(dirname);
@ -263,22 +299,27 @@ START_TEST(eio_test_monitor_directory_directory_created_notify)
}
END_TEST
static void _directory_deleted_cb(void* data, int type, void* event)
static void _directory_deleted_cb(void *data, int type, void *event)
{
ck_assert_int_eq(type, (int)EIO_MONITOR_DIRECTORY_DELETED);
_check_event_path(data, event);
_cancel_timeout();
ecore_main_loop_quit();
if (_check_event_path(data, event))
{
_cancel_timeout();
ecore_main_loop_quit();
}
}
START_TEST(eio_test_monitor_directory_directory_deleted_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Stringshare* filename;
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
filename = eina_stringshare_printf("%s/dircreated", dirname);
filename = eina_stringshare_printf("%s/eio_test_monitor_directory_directory_deleted_notify", dirname);
_create_directory((void*)filename);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
eio_monitor_add(dirname);
ecore_event_handler_add(EIO_MONITOR_DIRECTORY_DELETED, (Ecore_Event_Handler_Cb)_directory_deleted_cb, filename);
@ -291,23 +332,28 @@ START_TEST(eio_test_monitor_directory_directory_deleted_notify)
}
END_TEST
static void _directory_modified_cb(void* data, int type, void* event)
static void _directory_modified_cb(void *data, int type, void *event)
{
ck_assert_int_eq(type, (int)EIO_MONITOR_DIRECTORY_MODIFIED);
_check_event_path(data, event);
_cancel_timeout();
ecore_main_loop_quit();
if (_check_event_path(data, event))
{
_cancel_timeout();
ecore_main_loop_quit();
}
}
START_TEST(eio_test_monitor_directory_directory_modified_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Stringshare* filename;
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
filename = eina_stringshare_printf("%s/filecreated", dirname);
filename = eina_stringshare_printf("%s/eio_test_monitor_directory_directory_modified_notify", dirname);
_create_directory((void*)filename);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
eio_monitor_add(dirname);
ecore_event_handler_add(EIO_MONITOR_DIRECTORY_MODIFIED, (Ecore_Event_Handler_Cb)_directory_modified_cb, filename);
@ -321,18 +367,23 @@ START_TEST(eio_test_monitor_directory_directory_modified_notify)
END_TEST
static void _directory_self_deleted_cb(void* data, int type, void* event)
static void _directory_self_deleted_cb(void *data, int type, void *event)
{
ck_assert_int_eq(type, (int)EIO_MONITOR_SELF_DELETED);
_check_event_path(data, event);
_cancel_timeout();
ecore_main_loop_quit();
if (_check_event_path(data, event))
{
_cancel_timeout();
ecore_main_loop_quit();
}
}
START_TEST(eio_test_monitor_directory_directory_self_deleted_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Tmpstr *dirname = _common_init();
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
eio_monitor_add(dirname);
@ -350,12 +401,15 @@ END_TEST
START_TEST(eio_test_monitor_file_file_modified_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Stringshare* filename;
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
filename = eina_stringshare_printf("%s/filecreated", dirname);
_create_file((void*)filename);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
eio_monitor_add(filename);
ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, (Ecore_Event_Handler_Cb)_file_modified_cb, filename);
@ -371,12 +425,15 @@ END_TEST
START_TEST(eio_test_monitor_file_file_attrib_modified_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Stringshare* filename;
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
filename = eina_stringshare_printf("%s/filecreated", dirname);
filename = eina_stringshare_printf("%s/eio_test_monitor_file_file_attrib_modified_notify", dirname);
_create_file((void*)filename);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
eio_monitor_add(filename);
ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, (Ecore_Event_Handler_Cb)_file_modified_cb, filename);
@ -392,12 +449,15 @@ END_TEST
START_TEST(eio_test_monitor_file_file_closed_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Stringshare* filename;
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
filename = eina_stringshare_printf("%s/filecreated", dirname);
filename = eina_stringshare_printf("%s/eio_test_monitor_file_file_closed_notify", dirname);
_create_file((void*)filename);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
eio_monitor_add(dirname);
ecore_event_handler_add(EIO_MONITOR_FILE_CLOSED, (Ecore_Event_Handler_Cb)_file_closed_cb, filename);
@ -411,12 +471,15 @@ END_TEST
START_TEST(eio_test_monitor_file_file_self_deleted_notify)
{
Eina_Tmpstr* dirname = _common_init();
Eina_Stringshare* filename;
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
filename = eina_stringshare_printf("%s/filecreated", dirname);
filename = eina_stringshare_printf("%s/eio_test_monitor_file_file_self_deleted_notify", dirname);
_create_file((void*)filename);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
eio_monitor_add(filename);
ecore_event_handler_add(EIO_MONITOR_SELF_DELETED, (Ecore_Event_Handler_Cb)_directory_self_deleted_cb, filename);
@ -429,24 +492,189 @@ START_TEST(eio_test_monitor_file_file_self_deleted_notify)
}
END_TEST
START_TEST(eio_test_monitor_two_monitors_one_event)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Tmpstr *dirname2;
Eina_Stringshare *filename;
eina_file_mkdtemp("checkFileCreationXXXXXX", &dirname2);
filename = eina_stringshare_printf("%s/eio_test_monitor_two_monitors_one_event", dirname);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
eio_monitor_add(dirname);
eio_monitor_add(dirname2);
ecore_event_handler_add(EIO_MONITOR_FILE_CREATED, (Ecore_Event_Handler_Cb)_file_created_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _create_file, filename);
ecore_main_loop_begin();
_delete_directory((void*)dirname2);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_monitor_two_monitors_one_removed_one_event)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Tmpstr *dirname2;
Eina_Stringshare *filename;
Eio_Monitor *monitor;
eina_file_mkdtemp("checkFileCreationXXXXXX", &dirname2);
filename = eina_stringshare_printf("%s/eio_test_monitor_two_monitors_one_removed", dirname);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
monitor = eio_monitor_add(dirname2);
eio_monitor_add(dirname);
eio_monitor_del(monitor);
ecore_event_handler_add(EIO_MONITOR_FILE_CREATED, (Ecore_Event_Handler_Cb)_file_created_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _create_file, filename);
ecore_main_loop_begin();
_delete_directory((void*)dirname2);
_common_shutdown(dirname);
}
END_TEST
static void _unexpected_event_cb(void *data, int type, void *event)
{
ck_abort_msg("unexpected event");
}
START_TEST(eio_test_monitor_two_monitors_one_removed_no_event)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Tmpstr *dirname2;
Eina_Stringshare *filename;
Eio_Monitor *monitor;
eina_file_mkdtemp("checkFileCreationXXXXXX", &dirname2);
filename = eina_stringshare_printf("%s/eio_test_monitor_two_monitors_one_removed", dirname);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
monitor = eio_monitor_add(dirname);
eio_monitor_add(dirname2);
eio_monitor_del(monitor);
ecore_event_handler_add(EIO_MONITOR_FILE_CREATED, (Ecore_Event_Handler_Cb)_unexpected_event_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _create_file, filename);
ecore_timer_add(TEST_TIMEOUT_SEC - 1, _test_timeout_expected, NULL);
ecore_main_loop_begin();
_delete_directory((void*)dirname2);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_monitor_two_files_in_same_directory)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eina_Stringshare *filename2;
filename = eina_stringshare_printf("%s/eio_test_monitor_two_files_in_same_directory_1", dirname);
filename2 = eina_stringshare_printf("%s/eio_test_monitor_two_files_in_same_directory_2", dirname);
_create_file((void*)filename);
_create_file((void*)filename2);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
eio_monitor_add(filename);
eio_monitor_add(filename2);
ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, (Ecore_Event_Handler_Cb)_file_modified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _modify_file, filename);
ecore_main_loop_begin();
//cleanup
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_monitor_two_files_in_same_directory_one_removed)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eina_Stringshare *filename2;
Eio_Monitor *monitor;
filename = eina_stringshare_printf("%s/eio_test_monitor_two_files_in_same_directory_one_removed_1", dirname);
filename2 = eina_stringshare_printf("%s/eio_test_monitor_two_files_in_same_directory_one_removed_2", dirname);
_create_file((void*)filename);
_create_file((void*)filename2);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
monitor = eio_monitor_add(filename);
eio_monitor_add(filename2);
eio_monitor_del(monitor);
ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, (Ecore_Event_Handler_Cb)_unexpected_event_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _modify_file, filename);
ecore_timer_add(TEST_TIMEOUT_SEC - 1, _test_timeout_expected, NULL);
ecore_main_loop_begin();
//cleanup
_common_shutdown(dirname);
}
END_TEST
void eio_test_monitor(TCase *tc)
{
tcase_add_test(tc, eio_test_monitor_directory_file_created_notify);
tcase_add_test(tc, eio_test_monitor_directory_file_deleted_notify);
tcase_add_test(tc, eio_test_monitor_directory_file_modified_notify);
#ifndef _WIN32
#if !defined(_WIN32) && !defined(__MACH__)
tcase_add_test(tc, eio_test_monitor_directory_file_closed_notify);
#endif
tcase_add_test(tc, eio_test_monitor_directory_directory_created_notify);
tcase_add_test(tc, eio_test_monitor_directory_directory_deleted_notify);
tcase_add_test(tc, eio_test_monitor_directory_directory_modified_notify);
#ifndef __MACH__
tcase_add_test(tc, eio_test_monitor_directory_directory_self_deleted_notify);
#endif
tcase_add_test(tc, eio_test_monitor_file_file_modified_notify);
tcase_add_test(tc, eio_test_monitor_file_file_attrib_modified_notify);
#ifndef _WIN32
#if !defined(_WIN32) && !defined(__MACH__)
tcase_add_test(tc, eio_test_monitor_file_file_closed_notify);
#endif
#ifndef __MACH__
tcase_add_test(tc, eio_test_monitor_file_file_self_deleted_notify);
#endif
tcase_add_test(tc, eio_test_monitor_two_monitors_one_event);
tcase_add_test(tc, eio_test_monitor_two_monitors_one_removed_one_event);
tcase_add_test(tc, eio_test_monitor_two_monitors_one_removed_no_event);
tcase_add_test(tc, eio_test_monitor_two_files_in_same_directory);
tcase_add_test(tc, eio_test_monitor_two_files_in_same_directory_one_removed);
}