diff options
| author | Michael Albinus | 2015-11-25 15:00:06 +0100 |
|---|---|---|
| committer | Michael Albinus | 2015-11-25 15:07:12 +0100 |
| commit | bec57a486a2a40d7c770dab72a34cf6a4d17a5d0 (patch) | |
| tree | ab824a9c680a488764c8a7bcb975c2b3015c9d5a | |
| parent | 0247489fed0f70b2abf960de48bc4432381a581b (diff) | |
| download | emacs-bec57a486a2a40d7c770dab72a34cf6a4d17a5d0.tar.gz emacs-bec57a486a2a40d7c770dab72a34cf6a4d17a5d0.zip | |
Some final fixes in file notification before merging with master
* lisp/filenotify.el (file-notify--rm-descriptor): Remove WHAT arg.
(file-notify-callback): Improve check for `stopped' event. Call
`file-notify-rm-watch' rather than `file-notify--rm-descriptor'.
(file-notify-add-watch): In case FILE is not a directory, call the
file monitor for the kqueue backend. Otherwise, call the
directory monitor for the upper directory.
* src/inotify.c (inotifyevent_to_event): Extract file name from
watch_object if the event doesn't provide it.
(Finotify_add_watch): Add file name to watch_object.
* test/automated/file-notify-tests.el (file-notify--test-timeout):
Use different timeouts for different libraries.
(file-notify--test-with-events): Suppress lock files. Flush
outstanding events before running the body.
(file-notify-test02-events, file-notify-test04-file-validity): Do
not skip cygwin tests. Add additional test for file creation.
Adapt expected result for different backends.
(file-notify-test03-autorevert): Some of the tests don't work for
w32notify.
(file-notify-test06-many-events): Rename into both directions.
| -rw-r--r-- | lisp/filenotify.el | 36 | ||||
| -rw-r--r-- | src/inotify.c | 9 | ||||
| -rw-r--r-- | test/automated/file-notify-tests.el | 308 |
3 files changed, 239 insertions, 114 deletions
diff --git a/lisp/filenotify.el b/lisp/filenotify.el index 0d7a2b914c6..b6c1f686fe1 100644 --- a/lisp/filenotify.el +++ b/lisp/filenotify.el | |||
| @@ -49,17 +49,16 @@ handler. The value in the hash table is a list | |||
| 49 | Several values for a given DIR happen only for `inotify', when | 49 | Several values for a given DIR happen only for `inotify', when |
| 50 | different files from the same directory are watched.") | 50 | different files from the same directory are watched.") |
| 51 | 51 | ||
| 52 | (defun file-notify--rm-descriptor (descriptor &optional what) | 52 | (defun file-notify--rm-descriptor (descriptor) |
| 53 | "Remove DESCRIPTOR from `file-notify-descriptors'. | 53 | "Remove DESCRIPTOR from `file-notify-descriptors'. |
| 54 | DESCRIPTOR should be an object returned by `file-notify-add-watch'. | 54 | DESCRIPTOR should be an object returned by `file-notify-add-watch'. |
| 55 | If it is registered in `file-notify-descriptors', a stopped event is sent. | 55 | If it is registered in `file-notify-descriptors', a stopped event is sent." |
| 56 | WHAT is a file or directory name to be removed, needed just for `inotify'." | ||
| 57 | (let* ((desc (if (consp descriptor) (car descriptor) descriptor)) | 56 | (let* ((desc (if (consp descriptor) (car descriptor) descriptor)) |
| 58 | (file (if (consp descriptor) (cdr descriptor))) | 57 | (file (if (consp descriptor) (cdr descriptor))) |
| 59 | (registered (gethash desc file-notify-descriptors)) | 58 | (registered (gethash desc file-notify-descriptors)) |
| 60 | (dir (car registered))) | 59 | (dir (car registered))) |
| 61 | 60 | ||
| 62 | (when (and (consp registered) (or (null what) (string-equal dir what))) | 61 | (when (consp registered) |
| 63 | ;; Send `stopped' event. | 62 | ;; Send `stopped' event. |
| 64 | (dolist (entry (cdr registered)) | 63 | (dolist (entry (cdr registered)) |
| 65 | (funcall (cdr entry) | 64 | (funcall (cdr entry) |
| @@ -236,7 +235,6 @@ EVENT is the cadr of the event in `file-notify-handle-event' | |||
| 236 | (setq pending-event nil)) | 235 | (setq pending-event nil)) |
| 237 | 236 | ||
| 238 | ;; Check for stopped. | 237 | ;; Check for stopped. |
| 239 | ;;(message "file-notify-callback %S %S %S" file file1 registered) | ||
| 240 | (setq | 238 | (setq |
| 241 | stopped | 239 | stopped |
| 242 | (or | 240 | (or |
| @@ -244,10 +242,13 @@ EVENT is the cadr of the event in `file-notify-handle-event' | |||
| 244 | (and | 242 | (and |
| 245 | (memq action '(deleted renamed)) | 243 | (memq action '(deleted renamed)) |
| 246 | (= (length (cdr registered)) 1) | 244 | (= (length (cdr registered)) 1) |
| 247 | (string-equal | 245 | (or |
| 248 | (file-name-nondirectory file) | 246 | (string-equal |
| 249 | (or (file-name-nondirectory (car registered)) | 247 | (file-name-nondirectory file) |
| 250 | (car (cadr registered))))))) | 248 | (file-name-nondirectory (car registered))) |
| 249 | (string-equal | ||
| 250 | (file-name-nondirectory file) | ||
| 251 | (car (cadr registered))))))) | ||
| 251 | 252 | ||
| 252 | ;; Apply callback. | 253 | ;; Apply callback. |
| 253 | (when (and action | 254 | (when (and action |
| @@ -266,6 +267,9 @@ EVENT is the cadr of the event in `file-notify-handle-event' | |||
| 266 | (and (stringp file1) | 267 | (and (stringp file1) |
| 267 | (string-equal | 268 | (string-equal |
| 268 | (nth 0 entry) (file-name-nondirectory file1))))) | 269 | (nth 0 entry) (file-name-nondirectory file1))))) |
| 270 | ;;(message | ||
| 271 | ;;"file-notify-callback %S %S %S %S %S" | ||
| 272 | ;;(file-notify--descriptor desc file) action file file1 registered) | ||
| 269 | (if file1 | 273 | (if file1 |
| 270 | (funcall | 274 | (funcall |
| 271 | callback | 275 | callback |
| @@ -276,8 +280,7 @@ EVENT is the cadr of the event in `file-notify-handle-event' | |||
| 276 | 280 | ||
| 277 | ;; Modify `file-notify-descriptors'. | 281 | ;; Modify `file-notify-descriptors'. |
| 278 | (when stopped | 282 | (when stopped |
| 279 | (file-notify--rm-descriptor | 283 | (file-notify-rm-watch (file-notify--descriptor desc file)))))) |
| 280 | (file-notify--descriptor desc file) file))))) | ||
| 281 | 284 | ||
| 282 | ;; `kqueue', `gfilenotify' and `w32notify' return a unique descriptor | 285 | ;; `kqueue', `gfilenotify' and `w32notify' return a unique descriptor |
| 283 | ;; for every `file-notify-add-watch', while `inotify' returns a unique | 286 | ;; for every `file-notify-add-watch', while `inotify' returns a unique |
| @@ -342,7 +345,12 @@ FILE is the name of the file whose event is being reported." | |||
| 342 | ;; A file name handler could exist even if there is no local | 345 | ;; A file name handler could exist even if there is no local |
| 343 | ;; file notification support. | 346 | ;; file notification support. |
| 344 | (setq desc (funcall | 347 | (setq desc (funcall |
| 345 | handler 'file-notify-add-watch file flags callback)) | 348 | handler 'file-notify-add-watch |
| 349 | ;; kqueue does not report file changes in | ||
| 350 | ;; directory monitor. So we must watch the file | ||
| 351 | ;; itself. | ||
| 352 | (if (eq file-notify--library 'kqueue) file dir) | ||
| 353 | flags callback)) | ||
| 346 | 354 | ||
| 347 | ;; Check, whether Emacs has been compiled with file notification | 355 | ;; Check, whether Emacs has been compiled with file notification |
| 348 | ;; support. | 356 | ;; support. |
| @@ -379,7 +387,9 @@ FILE is the name of the file whose event is being reported." | |||
| 379 | l-flags))) | 387 | l-flags))) |
| 380 | 388 | ||
| 381 | ;; Call low-level function. | 389 | ;; Call low-level function. |
| 382 | (setq desc (funcall func file l-flags 'file-notify-callback))) | 390 | (setq desc (funcall |
| 391 | func (if (eq file-notify--library 'kqueue) file dir) | ||
| 392 | l-flags 'file-notify-callback))) | ||
| 383 | 393 | ||
| 384 | ;; Modify `file-notify-descriptors'. | 394 | ;; Modify `file-notify-descriptors'. |
| 385 | (setq file (unless (file-directory-p file) (file-name-nondirectory file)) | 395 | (setq file (unless (file-directory-p file) (file-name-nondirectory file)) |
diff --git a/src/inotify.c b/src/inotify.c index d1a80bbad1b..6577ee28cd1 100644 --- a/src/inotify.c +++ b/src/inotify.c | |||
| @@ -46,8 +46,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 46 | static int inotifyfd = -1; | 46 | static int inotifyfd = -1; |
| 47 | 47 | ||
| 48 | /* Assoc list of files being watched. | 48 | /* Assoc list of files being watched. |
| 49 | Format: | 49 | Format: (watch-descriptor name callback) |
| 50 | (watch-descriptor . callback) | ||
| 51 | */ | 50 | */ |
| 52 | static Lisp_Object watch_list; | 51 | static Lisp_Object watch_list; |
| 53 | 52 | ||
| @@ -106,12 +105,14 @@ inotifyevent_to_event (Lisp_Object watch_object, struct inotify_event const *ev) | |||
| 106 | name = make_unibyte_string (ev->name, min (len, ev->len)); | 105 | name = make_unibyte_string (ev->name, min (len, ev->len)); |
| 107 | name = DECODE_FILE (name); | 106 | name = DECODE_FILE (name); |
| 108 | } | 107 | } |
| 108 | else | ||
| 109 | name = XCAR (XCDR (watch_object)); | ||
| 109 | 110 | ||
| 110 | return list2 (list4 (make_watch_descriptor (ev->wd), | 111 | return list2 (list4 (make_watch_descriptor (ev->wd), |
| 111 | mask_to_aspects (ev->mask), | 112 | mask_to_aspects (ev->mask), |
| 112 | name, | 113 | name, |
| 113 | make_number (ev->cookie)), | 114 | make_number (ev->cookie)), |
| 114 | XCDR (watch_object)); | 115 | Fnth (make_number (2), watch_object)); |
| 115 | } | 116 | } |
| 116 | 117 | ||
| 117 | /* This callback is called when the FD is available for read. The inotify | 118 | /* This callback is called when the FD is available for read. The inotify |
| @@ -325,7 +326,7 @@ is managed internally and there is no corresponding inotify_init. Use | |||
| 325 | watch_list = Fdelete (watch_object, watch_list); | 326 | watch_list = Fdelete (watch_object, watch_list); |
| 326 | 327 | ||
| 327 | /* Store watch object in watch list. */ | 328 | /* Store watch object in watch list. */ |
| 328 | watch_object = Fcons (watch_descriptor, callback); | 329 | watch_object = list3 (watch_descriptor, encoded_file_name, callback); |
| 329 | watch_list = Fcons (watch_object, watch_list); | 330 | watch_list = Fcons (watch_object, watch_list); |
| 330 | 331 | ||
| 331 | return watch_descriptor; | 332 | return watch_descriptor; |
diff --git a/test/automated/file-notify-tests.el b/test/automated/file-notify-tests.el index 7bacddd8855..b665dddb631 100644 --- a/test/automated/file-notify-tests.el +++ b/test/automated/file-notify-tests.el | |||
| @@ -65,7 +65,11 @@ | |||
| 65 | 65 | ||
| 66 | (defun file-notify--test-timeout () | 66 | (defun file-notify--test-timeout () |
| 67 | "Timeout to wait for arriving events, in seconds." | 67 | "Timeout to wait for arriving events, in seconds." |
| 68 | (if (file-remote-p temporary-file-directory) 6 3)) | 68 | (cond |
| 69 | ((file-remote-p temporary-file-directory) 6) | ||
| 70 | ((string-equal (file-notify--test-library) "w32notify") 20) | ||
| 71 | ((eq system-type 'cygwin) 10) | ||
| 72 | (t 3))) | ||
| 69 | 73 | ||
| 70 | (defun file-notify--test-cleanup () | 74 | (defun file-notify--test-cleanup () |
| 71 | "Cleanup after a test." | 75 | "Cleanup after a test." |
| @@ -262,7 +266,7 @@ and the event to `file-notify--test-events'." | |||
| 262 | (let* ((file-notify--test-event event) | 266 | (let* ((file-notify--test-event event) |
| 263 | (result | 267 | (result |
| 264 | (ert-run-test (make-ert-test :body 'file-notify--test-event-test)))) | 268 | (ert-run-test (make-ert-test :body 'file-notify--test-event-test)))) |
| 265 | ;; Do not add temporary files, this would confuse the checks. | 269 | ;; Do not add lock files, this would confuse the checks. |
| 266 | (unless (string-match | 270 | (unless (string-match |
| 267 | (regexp-quote ".#") | 271 | (regexp-quote ".#") |
| 268 | (file-notify--event-file-name file-notify--test-event)) | 272 | (file-notify--event-file-name file-notify--test-event)) |
| @@ -289,9 +293,14 @@ TIMEOUT is the maximum time to wait for, in seconds." | |||
| 289 | Don't wait longer than timeout seconds for the events to be delivered." | 293 | Don't wait longer than timeout seconds for the events to be delivered." |
| 290 | (declare (indent 1)) | 294 | (declare (indent 1)) |
| 291 | (let ((outer (make-symbol "outer"))) | 295 | (let ((outer (make-symbol "outer"))) |
| 292 | `(let ((,outer file-notify--test-events)) | 296 | `(let ((,outer file-notify--test-events) |
| 297 | create-lockfiles) | ||
| 293 | (setq file-notify--test-expected-events | 298 | (setq file-notify--test-expected-events |
| 294 | (append file-notify--test-expected-events ,events)) | 299 | (append file-notify--test-expected-events ,events)) |
| 300 | ;; Flush pending events. | ||
| 301 | (file-notify--wait-for-events | ||
| 302 | (file-notify--test-timeout) | ||
| 303 | (input-pending-p)) | ||
| 295 | (let (file-notify--test-events) | 304 | (let (file-notify--test-events) |
| 296 | ,@body | 305 | ,@body |
| 297 | (file-notify--wait-for-events | 306 | (file-notify--wait-for-events |
| @@ -305,11 +314,34 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 305 | (ert-deftest file-notify-test02-events () | 314 | (ert-deftest file-notify-test02-events () |
| 306 | "Check file creation/change/removal notifications." | 315 | "Check file creation/change/removal notifications." |
| 307 | (skip-unless (file-notify--test-local-enabled)) | 316 | (skip-unless (file-notify--test-local-enabled)) |
| 308 | ;; Under cygwin there are so bad timings that it doesn't make sense to test. | ||
| 309 | (skip-unless (not (eq system-type 'cygwin))) | ||
| 310 | 317 | ||
| 311 | (unwind-protect | 318 | (unwind-protect |
| 312 | (progn | 319 | (progn |
| 320 | ;; Check file creation, change and deletion. It doesn't work | ||
| 321 | ;; for cygwin and kqueue, because we don't use an implicit | ||
| 322 | ;; directory monitor (kqueue), or the timings are too bad (cygwin). | ||
| 323 | (unless (or (eq system-type 'cygwin) | ||
| 324 | (string-equal (file-notify--test-library) "kqueue")) | ||
| 325 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)) | ||
| 326 | (should | ||
| 327 | (setq file-notify--test-desc | ||
| 328 | (file-notify-add-watch | ||
| 329 | file-notify--test-tmpfile | ||
| 330 | '(change) 'file-notify--test-event-handler))) | ||
| 331 | (file-notify--test-with-events | ||
| 332 | (cond | ||
| 333 | ;; cygwin recognizes only `deleted' and `stopped' events. | ||
| 334 | ((eq system-type 'cygwin) | ||
| 335 | '(deleted stopped)) | ||
| 336 | (t '(created changed deleted stopped))) | ||
| 337 | (write-region | ||
| 338 | "another text" nil file-notify--test-tmpfile nil 'no-message) | ||
| 339 | (read-event nil nil 0.1) | ||
| 340 | (delete-file file-notify--test-tmpfile)) | ||
| 341 | ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it. | ||
| 342 | (let (file-notify--test-events) | ||
| 343 | (file-notify-rm-watch file-notify--test-desc))) | ||
| 344 | |||
| 313 | ;; Check file change and deletion. | 345 | ;; Check file change and deletion. |
| 314 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)) | 346 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)) |
| 315 | (write-region "any text" nil file-notify--test-tmpfile nil 'no-message) | 347 | (write-region "any text" nil file-notify--test-tmpfile nil 'no-message) |
| @@ -318,9 +350,23 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 318 | (file-notify-add-watch | 350 | (file-notify-add-watch |
| 319 | file-notify--test-tmpfile | 351 | file-notify--test-tmpfile |
| 320 | '(change) 'file-notify--test-event-handler))) | 352 | '(change) 'file-notify--test-event-handler))) |
| 321 | (file-notify--test-with-events '(changed deleted) | 353 | (file-notify--test-with-events |
| 354 | (cond | ||
| 355 | ;; cygwin recognizes only `deleted' and `stopped' events. | ||
| 356 | ((eq system-type 'cygwin) | ||
| 357 | '(deleted stopped)) | ||
| 358 | ;; inotify, kqueueg and gfilenotify raise just one | ||
| 359 | ;; `changed' event, the other backends show us two of | ||
| 360 | ;; them. | ||
| 361 | ((or (string-equal "inotify" (file-notify--test-library)) | ||
| 362 | (string-equal "kqueue" (file-notify--test-library)) | ||
| 363 | (string-equal "gfilenotify" (file-notify--test-library))) | ||
| 364 | '(changed deleted stopped)) | ||
| 365 | (t '(changed changed deleted stopped))) | ||
| 366 | (read-event nil nil 0.1) | ||
| 322 | (write-region | 367 | (write-region |
| 323 | "another text" nil file-notify--test-tmpfile nil 'no-message) | 368 | "another text" nil file-notify--test-tmpfile nil 'no-message) |
| 369 | (read-event nil nil 0.1) | ||
| 324 | (delete-file file-notify--test-tmpfile)) | 370 | (delete-file file-notify--test-tmpfile)) |
| 325 | ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it. | 371 | ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it. |
| 326 | (let (file-notify--test-events) | 372 | (let (file-notify--test-events) |
| @@ -328,29 +374,37 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 328 | 374 | ||
| 329 | ;; Check file creation, change and deletion when watching a | 375 | ;; Check file creation, change and deletion when watching a |
| 330 | ;; directory. There must be a `stopped' event when deleting | 376 | ;; directory. There must be a `stopped' event when deleting |
| 331 | ;; the directory. It doesn't work for w32notify. | 377 | ;; the directory. |
| 332 | (unless (string-equal (file-notify--test-library) "w32notify") | 378 | (let ((temporary-file-directory |
| 333 | (let ((temporary-file-directory | 379 | (make-temp-file "file-notify-test-parent" t))) |
| 334 | (make-temp-file "file-notify-test-parent" t))) | 380 | (should |
| 335 | (should | 381 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name) |
| 336 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name) | 382 | file-notify--test-desc |
| 337 | file-notify--test-desc | 383 | (file-notify-add-watch |
| 338 | (file-notify-add-watch | 384 | temporary-file-directory |
| 339 | temporary-file-directory | 385 | '(change) 'file-notify--test-event-handler))) |
| 340 | '(change) 'file-notify--test-event-handler))) | 386 | (file-notify--test-with-events |
| 341 | (file-notify--test-with-events | 387 | (cond |
| 342 | ;; There are two `deleted' events, for the file and | 388 | ;; w32notify does raise a `stopped' event when a |
| 343 | ;; for the directory. Except for kqueue. | 389 | ;; watched directory is deleted. |
| 344 | (if (string-equal (file-notify--test-library) "kqueue") | 390 | ((string-equal (file-notify--test-library) "w32notify") |
| 345 | '(created changed deleted stopped) | 391 | '(created changed deleted)) |
| 346 | '(created changed deleted deleted stopped)) | 392 | ;; cygwin recognizes only `deleted' and `stopped' events. |
| 347 | (write-region | 393 | ((eq system-type 'cygwin) |
| 348 | "any text" nil file-notify--test-tmpfile nil 'no-message) | 394 | '(deleted stopped)) |
| 349 | (read-event nil nil 0.1) | 395 | ;; There are two `deleted' events, for the file and for |
| 350 | (delete-directory temporary-file-directory 'recursive)) | 396 | ;; the directory. Except for kqueue. |
| 351 | ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it. | 397 | ((string-equal (file-notify--test-library) "kqueue") |
| 352 | (let (file-notify--test-events) | 398 | '(created changed deleted stopped)) |
| 353 | (file-notify-rm-watch file-notify--test-desc)))) | 399 | (t '(created changed deleted deleted stopped))) |
| 400 | (read-event nil nil 0.1) | ||
| 401 | (write-region | ||
| 402 | "any text" nil file-notify--test-tmpfile nil 'no-message) | ||
| 403 | (read-event nil nil 0.1) | ||
| 404 | (delete-directory temporary-file-directory 'recursive)) | ||
| 405 | ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it. | ||
| 406 | (let (file-notify--test-events) | ||
| 407 | (file-notify-rm-watch file-notify--test-desc))) | ||
| 354 | 408 | ||
| 355 | ;; Check copy of files inside a directory. | 409 | ;; Check copy of files inside a directory. |
| 356 | (let ((temporary-file-directory | 410 | (let ((temporary-file-directory |
| @@ -363,11 +417,22 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 363 | temporary-file-directory | 417 | temporary-file-directory |
| 364 | '(change) 'file-notify--test-event-handler))) | 418 | '(change) 'file-notify--test-event-handler))) |
| 365 | (file-notify--test-with-events | 419 | (file-notify--test-with-events |
| 366 | ;; w32notify does not distinguish between `changed' and | 420 | (cond |
| 367 | ;; `attribute-changed'. | 421 | ;; w32notify does not distinguish between `changed' and |
| 368 | (if (string-equal (file-notify--test-library) "w32notify") | 422 | ;; `attribute-changed'. |
| 369 | '(created changed changed deleted) | 423 | ((string-equal (file-notify--test-library) "w32notify") |
| 424 | '(created changed created changed changed changed changed | ||
| 425 | deleted deleted)) | ||
| 426 | ;; cygwin recognizes only `deleted' and `stopped' events. | ||
| 427 | ((eq system-type 'cygwin) | ||
| 428 | '(deleted stopped)) | ||
| 429 | ;; There are three `deleted' events, for two files and | ||
| 430 | ;; for the directory. Except for kqueue. | ||
| 431 | ((string-equal (file-notify--test-library) "kqueue") | ||
| 370 | '(created changed created changed deleted stopped)) | 432 | '(created changed created changed deleted stopped)) |
| 433 | (t '(created changed created changed | ||
| 434 | deleted deleted deleted stopped))) | ||
| 435 | (read-event nil nil 0.1) | ||
| 371 | (write-region | 436 | (write-region |
| 372 | "any text" nil file-notify--test-tmpfile nil 'no-message) | 437 | "any text" nil file-notify--test-tmpfile nil 'no-message) |
| 373 | (read-event nil nil 0.1) | 438 | (read-event nil nil 0.1) |
| @@ -393,7 +458,21 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 393 | (file-notify-add-watch | 458 | (file-notify-add-watch |
| 394 | temporary-file-directory | 459 | temporary-file-directory |
| 395 | '(change) 'file-notify--test-event-handler))) | 460 | '(change) 'file-notify--test-event-handler))) |
| 396 | (file-notify--test-with-events '(created changed renamed) | 461 | (file-notify--test-with-events |
| 462 | (cond | ||
| 463 | ;; w32notify does not distinguish between `changed' and | ||
| 464 | ;; `attribute-changed'. | ||
| 465 | ((string-equal (file-notify--test-library) "w32notify") | ||
| 466 | '(created changed renamed deleted)) | ||
| 467 | ;; cygwin recognizes only `deleted' and `stopped' events. | ||
| 468 | ((eq system-type 'cygwin) | ||
| 469 | '(deleted stopped)) | ||
| 470 | ;; There are two `deleted' events, for the file and for | ||
| 471 | ;; the directory. Except for kqueue. | ||
| 472 | ((string-equal (file-notify--test-library) "kqueue") | ||
| 473 | '(created changed renamed deleted stopped)) | ||
| 474 | (t '(created changed renamed deleted deleted stopped))) | ||
| 475 | (read-event nil nil 0.1) | ||
| 397 | (write-region | 476 | (write-region |
| 398 | "any text" nil file-notify--test-tmpfile nil 'no-message) | 477 | "any text" nil file-notify--test-tmpfile nil 'no-message) |
| 399 | (read-event nil nil 0.1) | 478 | (read-event nil nil 0.1) |
| @@ -405,30 +484,37 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 405 | (let (file-notify--test-events) | 484 | (let (file-notify--test-events) |
| 406 | (file-notify-rm-watch file-notify--test-desc))) | 485 | (file-notify-rm-watch file-notify--test-desc))) |
| 407 | 486 | ||
| 408 | ;; Check attribute change. It doesn't work for kqueue and w32notify. | 487 | ;; Check attribute change. Does not work for cygwin. |
| 409 | (unless (or (string-equal (file-notify--test-library) "kqueue") | 488 | (unless (eq system-type 'cygwin) |
| 410 | (string-equal (file-notify--test-library) "w32notify")) | 489 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)) |
| 490 | (write-region | ||
| 491 | "any text" nil file-notify--test-tmpfile nil 'no-message) | ||
| 411 | (should | 492 | (should |
| 412 | (setq file-notify--test-desc | 493 | (setq file-notify--test-desc |
| 413 | (file-notify-add-watch | 494 | (file-notify-add-watch |
| 414 | file-notify--test-tmpfile | 495 | file-notify--test-tmpfile |
| 415 | '(attribute-change) 'file-notify--test-event-handler))) | 496 | '(attribute-change) 'file-notify--test-event-handler))) |
| 416 | (file-notify--test-with-events | 497 | (file-notify--test-with-events |
| 417 | (if (file-remote-p temporary-file-directory) | 498 | (cond |
| 418 | ;; In the remote case, `write-region' raises also an | 499 | ;; w32notify does not distinguish between `changed' and |
| 419 | ;; `attribute-changed' event. | 500 | ;; `attribute-changed'. |
| 420 | '(attribute-changed attribute-changed attribute-changed) | 501 | ((string-equal (file-notify--test-library) "w32notify") |
| 421 | '(attribute-changed attribute-changed)) | 502 | '(changed changed changed changed)) |
| 422 | ;; We must use short delays between the operations. | 503 | ;; For kqueue and in the remote case, `write-region' |
| 423 | ;; Otherwise, not all events arrive us in the remote case. | 504 | ;; raises also an `attribute-changed' event. |
| 424 | (write-region | 505 | ((or (string-equal (file-notify--test-library) "kqueue") |
| 425 | "any text" nil file-notify--test-tmpfile nil 'no-message) | 506 | (file-remote-p temporary-file-directory)) |
| 426 | (read-event nil nil 0.1) | 507 | '(attribute-changed attribute-changed attribute-changed)) |
| 427 | (set-file-modes file-notify--test-tmpfile 000) | 508 | (t '(attribute-changed attribute-changed))) |
| 428 | (read-event nil nil 0.1) | 509 | (read-event nil nil 0.1) |
| 429 | (set-file-times file-notify--test-tmpfile '(0 0)) | 510 | (write-region |
| 430 | (read-event nil nil 0.1) | 511 | "any text" nil file-notify--test-tmpfile nil 'no-message) |
| 431 | (delete-file file-notify--test-tmpfile)) | 512 | (read-event nil nil 0.1) |
| 513 | (set-file-modes file-notify--test-tmpfile 000) | ||
| 514 | (read-event nil nil 0.1) | ||
| 515 | (set-file-times file-notify--test-tmpfile '(0 0)) | ||
| 516 | (read-event nil nil 0.1) | ||
| 517 | (delete-file file-notify--test-tmpfile)) | ||
| 432 | ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it. | 518 | ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it. |
| 433 | (let (file-notify--test-events) | 519 | (let (file-notify--test-events) |
| 434 | (file-notify-rm-watch file-notify--test-desc))) | 520 | (file-notify-rm-watch file-notify--test-desc))) |
| @@ -504,28 +590,31 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 504 | (should (string-match "another text" (buffer-string))) | 590 | (should (string-match "another text" (buffer-string))) |
| 505 | 591 | ||
| 506 | ;; Stop file notification. Autorevert shall still work via polling. | 592 | ;; Stop file notification. Autorevert shall still work via polling. |
| 507 | (file-notify-rm-watch auto-revert-notify-watch-descriptor) | 593 | ;; It doesn't work for `w32notify'. |
| 508 | (file-notify--wait-for-events | 594 | (unless (string-equal (file-notify--test-library) "w32notify") |
| 509 | timeout (null auto-revert-use-notify)) | 595 | (file-notify-rm-watch auto-revert-notify-watch-descriptor) |
| 510 | (should-not auto-revert-use-notify) | ||
| 511 | (should-not auto-revert-notify-watch-descriptor) | ||
| 512 | |||
| 513 | ;; Modify file. We wait for two seconds, in order to have | ||
| 514 | ;; another timestamp. One second seems to be too short. | ||
| 515 | (with-current-buffer (get-buffer-create "*Messages*") | ||
| 516 | (narrow-to-region (point-max) (point-max))) | ||
| 517 | (sleep-for 2) | ||
| 518 | (write-region | ||
| 519 | "foo bla" nil file-notify--test-tmpfile nil 'no-message) | ||
| 520 | |||
| 521 | ;; Check, that the buffer has been reverted. | ||
| 522 | (with-current-buffer (get-buffer-create "*Messages*") | ||
| 523 | (file-notify--wait-for-events | 596 | (file-notify--wait-for-events |
| 524 | timeout | 597 | timeout (null auto-revert-use-notify)) |
| 525 | (string-match | 598 | (should-not auto-revert-use-notify) |
| 526 | (format-message "Reverting buffer `%s'." (buffer-name buf)) | 599 | (should-not auto-revert-notify-watch-descriptor) |
| 527 | (buffer-string)))) | 600 | |
| 528 | (should (string-match "foo bla" (buffer-string))))) | 601 | ;; Modify file. We wait for two seconds, in order to |
| 602 | ;; have another timestamp. One second seems to be too | ||
| 603 | ;; short. | ||
| 604 | (with-current-buffer (get-buffer-create "*Messages*") | ||
| 605 | (narrow-to-region (point-max) (point-max))) | ||
| 606 | (sleep-for 2) | ||
| 607 | (write-region | ||
| 608 | "foo bla" nil file-notify--test-tmpfile nil 'no-message) | ||
| 609 | |||
| 610 | ;; Check, that the buffer has been reverted. | ||
| 611 | (with-current-buffer (get-buffer-create "*Messages*") | ||
| 612 | (file-notify--wait-for-events | ||
| 613 | timeout | ||
| 614 | (string-match | ||
| 615 | (format-message "Reverting buffer `%s'." (buffer-name buf)) | ||
| 616 | (buffer-string)))) | ||
| 617 | (should (string-match "foo bla" (buffer-string)))))) | ||
| 529 | 618 | ||
| 530 | ;; Cleanup. | 619 | ;; Cleanup. |
| 531 | (with-current-buffer "*Messages*" (widen)) | 620 | (with-current-buffer "*Messages*" (widen)) |
| @@ -538,8 +627,6 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 538 | (ert-deftest file-notify-test04-file-validity () | 627 | (ert-deftest file-notify-test04-file-validity () |
| 539 | "Check `file-notify-valid-p' for files." | 628 | "Check `file-notify-valid-p' for files." |
| 540 | (skip-unless (file-notify--test-local-enabled)) | 629 | (skip-unless (file-notify--test-local-enabled)) |
| 541 | ;; Under cygwin there are so bad timings that it doesn't make sense to test. | ||
| 542 | (skip-unless (not (eq system-type 'cygwin))) | ||
| 543 | 630 | ||
| 544 | (unwind-protect | 631 | (unwind-protect |
| 545 | (progn | 632 | (progn |
| @@ -569,7 +656,20 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 569 | (file-notify-add-watch | 656 | (file-notify-add-watch |
| 570 | file-notify--test-tmpfile | 657 | file-notify--test-tmpfile |
| 571 | '(change) #'file-notify--test-event-handler))) | 658 | '(change) #'file-notify--test-event-handler))) |
| 572 | (file-notify--test-with-events '(changed deleted) | 659 | (file-notify--test-with-events |
| 660 | (cond | ||
| 661 | ;; cygwin recognizes only `deleted' and `stopped' events. | ||
| 662 | ((eq system-type 'cygwin) | ||
| 663 | '(deleted stopped)) | ||
| 664 | ;; inotify, kqueueg and gfilenotify raise just one | ||
| 665 | ;; `changed' event, the other backends show us two of | ||
| 666 | ;; them. | ||
| 667 | ((or (string-equal "inotify" (file-notify--test-library)) | ||
| 668 | (string-equal "kqueue" (file-notify--test-library)) | ||
| 669 | (string-equal "gfilenotify" (file-notify--test-library))) | ||
| 670 | '(changed deleted stopped)) | ||
| 671 | (t '(changed changed deleted stopped))) | ||
| 672 | (read-event nil nil 0.1) | ||
| 573 | (should (file-notify-valid-p file-notify--test-desc)) | 673 | (should (file-notify-valid-p file-notify--test-desc)) |
| 574 | (write-region | 674 | (write-region |
| 575 | "another text" nil file-notify--test-tmpfile nil 'no-message) | 675 | "another text" nil file-notify--test-tmpfile nil 'no-message) |
| @@ -583,10 +683,10 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 583 | (file-notify--test-cleanup)) | 683 | (file-notify--test-cleanup)) |
| 584 | 684 | ||
| 585 | (unwind-protect | 685 | (unwind-protect |
| 586 | ;; The batch-mode operation of w32notify is fragile (there's no | 686 | ;; w32notify does not send a `stopped' event when deleting a |
| 587 | ;; input threads to send the message to). | 687 | ;; directory. The test does not work, therefore. |
| 588 | (unless (string-equal (file-notify--test-library) "w32notify") | 688 | (unless (string-equal (file-notify--test-library) "w32notify") |
| 589 | (let ((temporary-file-directory | 689 | (let ((temporary-file-directory |
| 590 | (make-temp-file "file-notify-test-parent" t))) | 690 | (make-temp-file "file-notify-test-parent" t))) |
| 591 | (should | 691 | (should |
| 592 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name) | 692 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name) |
| @@ -594,20 +694,25 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 594 | (file-notify-add-watch | 694 | (file-notify-add-watch |
| 595 | temporary-file-directory | 695 | temporary-file-directory |
| 596 | '(change) #'file-notify--test-event-handler))) | 696 | '(change) #'file-notify--test-event-handler))) |
| 597 | (file-notify--test-with-events | 697 | (file-notify--test-with-events |
| 598 | ;; There are two `deleted' events, for the file and for | 698 | (cond |
| 599 | ;; the directory. Except for kqueue. | 699 | ;; cygwin recognizes only `deleted' and `stopped' events. |
| 600 | (if (string-equal (file-notify--test-library) "kqueue") | 700 | ((eq system-type 'cygwin) |
| 601 | '(created changed deleted stopped) | 701 | '(deleted stopped)) |
| 602 | '(created changed deleted deleted stopped)) | 702 | ;; There are two `deleted' events, for the file and for |
| 603 | (should (file-notify-valid-p file-notify--test-desc)) | 703 | ;; the directory. Except for kqueue. |
| 604 | (write-region | 704 | ((string-equal (file-notify--test-library) "kqueue") |
| 605 | "any text" nil file-notify--test-tmpfile nil 'no-message) | 705 | '(created changed deleted stopped)) |
| 606 | (read-event nil nil 0.1) | 706 | (t '(created changed deleted deleted stopped))) |
| 707 | (should (file-notify-valid-p file-notify--test-desc)) | ||
| 708 | (read-event nil nil 0.1) | ||
| 709 | (write-region | ||
| 710 | "any text" nil file-notify--test-tmpfile nil 'no-message) | ||
| 711 | (read-event nil nil 0.1) | ||
| 607 | (delete-directory temporary-file-directory t)) | 712 | (delete-directory temporary-file-directory t)) |
| 608 | ;; After deleting the parent directory, the descriptor must | 713 | ;; After deleting the parent directory, the descriptor must |
| 609 | ;; not be valid anymore. | 714 | ;; not be valid anymore. |
| 610 | (should-not (file-notify-valid-p file-notify--test-desc)))) | 715 | (should-not (file-notify-valid-p file-notify--test-desc)))) |
| 611 | 716 | ||
| 612 | ;; Cleanup. | 717 | ;; Cleanup. |
| 613 | (file-notify--test-cleanup))) | 718 | (file-notify--test-cleanup))) |
| @@ -659,7 +764,7 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 659 | ;; valid anymore. | 764 | ;; valid anymore. |
| 660 | (delete-directory file-notify--test-tmpfile t) | 765 | (delete-directory file-notify--test-tmpfile t) |
| 661 | (file-notify--wait-for-events | 766 | (file-notify--wait-for-events |
| 662 | (file-notify--test-timeout) | 767 | (file-notify--test-timeout) |
| 663 | (not (file-notify-valid-p file-notify--test-desc))) | 768 | (not (file-notify-valid-p file-notify--test-desc))) |
| 664 | (should-not (file-notify-valid-p file-notify--test-desc))) | 769 | (should-not (file-notify-valid-p file-notify--test-desc))) |
| 665 | 770 | ||
| @@ -672,8 +777,9 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 672 | (ert-deftest file-notify-test06-many-events () | 777 | (ert-deftest file-notify-test06-many-events () |
| 673 | "Check that events are not dropped." | 778 | "Check that events are not dropped." |
| 674 | (skip-unless (file-notify--test-local-enabled)) | 779 | (skip-unless (file-notify--test-local-enabled)) |
| 675 | ;; Under cygwin there are so bad timings that it doesn't make sense to test. | 780 | ;; Under cygwin events arrive in random order. Impossible to define a test. |
| 676 | (skip-unless (not (eq system-type 'cygwin))) | 781 | (skip-unless (not (eq system-type 'cygwin))) |
| 782 | |||
| 677 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)) | 783 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)) |
| 678 | (make-directory file-notify--test-tmpfile) | 784 | (make-directory file-notify--test-tmpfile) |
| 679 | (should | 785 | (should |
| @@ -699,10 +805,18 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 699 | (let ((source-file-list source-file-list) | 805 | (let ((source-file-list source-file-list) |
| 700 | (target-file-list target-file-list)) | 806 | (target-file-list target-file-list)) |
| 701 | (while (and source-file-list target-file-list) | 807 | (while (and source-file-list target-file-list) |
| 808 | (read-event nil nil 0.1) | ||
| 702 | (write-region "" nil (pop source-file-list) nil 'no-message) | 809 | (write-region "" nil (pop source-file-list) nil 'no-message) |
| 703 | (read-event nil nil 0.1) | 810 | (read-event nil nil 0.1) |
| 704 | (write-region "" nil (pop target-file-list) nil 'no-message)))) | 811 | (write-region "" nil (pop target-file-list) nil 'no-message)))) |
| 705 | (file-notify--test-with-events (make-list n 'renamed) | 812 | (file-notify--test-with-events |
| 813 | (cond | ||
| 814 | ;; w32notify fires both `deleted' and `renamed' events. | ||
| 815 | ((string-equal (file-notify--test-library) "w32notify") | ||
| 816 | (let (r) | ||
| 817 | (dotimes (i n r) | ||
| 818 | (setq r (append '(deleted renamed) r))))) | ||
| 819 | (t (make-list n 'renamed))) | ||
| 706 | (let ((source-file-list source-file-list) | 820 | (let ((source-file-list source-file-list) |
| 707 | (target-file-list target-file-list)) | 821 | (target-file-list target-file-list)) |
| 708 | (while (and source-file-list target-file-list) | 822 | (while (and source-file-list target-file-list) |
| @@ -725,7 +839,7 @@ Don't wait longer than timeout seconds for the events to be delivered." | |||
| 725 | ;; TODO: | 839 | ;; TODO: |
| 726 | 840 | ||
| 727 | ;; * For w32notify, no stopped events arrive when a directory is removed. | 841 | ;; * For w32notify, no stopped events arrive when a directory is removed. |
| 728 | ;; * Try to handle arriving events under cygwin reliably. | 842 | ;; * Check, why cygwin recognizes only `deleted' and `stopped' events. |
| 729 | 843 | ||
| 730 | (provide 'file-notify-tests) | 844 | (provide 'file-notify-tests) |
| 731 | ;;; file-notify-tests.el ends here | 845 | ;;; file-notify-tests.el ends here |