Sync NEWS with the documentation
[emacs.git] / test / lisp / filenotify-tests.el
blob3456d31fda953c18320176932a76389a56d9045f
1 ;;; filenotify-tests.el --- Tests of file notifications -*- lexical-binding: t; -*-
3 ;; Copyright (C) 2013-2017 Free Software Foundation, Inc.
5 ;; Author: Michael Albinus <michael.albinus@gmx.de>
7 ;; This program is free software: you can redistribute it and/or
8 ;; modify it under the terms of the GNU General Public License as
9 ;; published by the Free Software Foundation, either version 3 of the
10 ;; License, or (at your option) any later version.
12 ;; This program is distributed in the hope that it will be useful, but
13 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ;; General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with this program. If not, see `http://www.gnu.org/licenses/'.
20 ;;; Commentary:
22 ;; Some of the tests require access to a remote host files. Since
23 ;; this could be problematic, a mock-up connection method "mock" is
24 ;; used. Emulating a remote connection, it simply calls "sh -i".
25 ;; Tramp's file name handlers still run, so this test is sufficient
26 ;; except for connection establishing.
28 ;; If you want to test a real Tramp connection, set
29 ;; $REMOTE_TEMPORARY_FILE_DIRECTORY to a suitable value in order to
30 ;; overwrite the default value. If you want to skip tests accessing a
31 ;; remote host, set this environment variable to "/dev/null" or
32 ;; whatever is appropriate on your system.
34 ;; A whole test run can be performed calling the command `file-notify-test-all'.
36 ;;; Code:
38 (require 'ert)
39 (require 'ert-x)
40 (require 'filenotify)
41 (require 'tramp)
43 ;; There is no default value on w32 systems, which could work out of the box.
44 (defconst file-notify-test-remote-temporary-file-directory
45 (cond
46 ((getenv "REMOTE_TEMPORARY_FILE_DIRECTORY"))
47 ((eq system-type 'windows-nt) null-device)
48 (t (add-to-list
49 'tramp-methods
50 '("mock"
51 (tramp-login-program "sh")
52 (tramp-login-args (("-i")))
53 (tramp-remote-shell "/bin/sh")
54 (tramp-remote-shell-args ("-c"))
55 (tramp-connection-timeout 10)))
56 (add-to-list
57 'tramp-default-host-alist
58 `("\\`mock\\'" nil ,(system-name)))
59 ;; Emacs' Makefile sets $HOME to a nonexistent value. Needed in
60 ;; batch mode only, therefore.
61 (unless (and (null noninteractive) (file-directory-p "~/"))
62 (setenv "HOME" temporary-file-directory))
63 (format "/mock::%s" temporary-file-directory)))
64 "Temporary directory for Tramp tests.")
66 (defvar file-notify--test-tmpfile nil)
67 (defvar file-notify--test-tmpfile1 nil)
68 (defvar file-notify--test-desc nil)
69 (defvar file-notify--test-desc1 nil)
70 (defvar file-notify--test-desc2 nil)
71 (defvar file-notify--test-results nil)
72 (defvar file-notify--test-event nil)
73 (defvar file-notify--test-events nil)
74 (defvar file-notify--test-monitors nil)
76 (defun file-notify--test-read-event ()
77 "Read one event.
78 There are different timeouts for local and remote file notification libraries."
79 (read-event
80 nil nil
81 (cond
82 ;; gio/gpollfilemonitor.c declares POLL_TIME_SECS 5. So we must
83 ;; wait at least this time in the GPollFileMonitor case. A
84 ;; similar timeout seems to be needed in the GFamFileMonitor case,
85 ;; at least on Cygwin.
86 ((and (string-equal (file-notify--test-library) "gfilenotify")
87 (memq (file-notify--test-monitor)
88 '(GFamFileMonitor GPollFileMonitor)))
90 ((string-equal (file-notify--test-library) "gvfs-monitor-dir.exe") 1)
91 ((file-remote-p temporary-file-directory) 0.1)
92 (t 0.01))))
94 (defun file-notify--test-timeout ()
95 "Timeout to wait for arriving a bunch of events, in seconds."
96 (cond
97 ((file-remote-p temporary-file-directory) 6)
98 ((string-equal (file-notify--test-library) "w32notify") 4)
99 ((eq system-type 'cygwin) 6)
100 (t 3)))
102 (defmacro file-notify--wait-for-events (timeout until)
103 "Wait for and return file notification events until form UNTIL is true.
104 TIMEOUT is the maximum time to wait for, in seconds."
105 `(with-timeout (,timeout (ignore))
106 (while (null ,until)
107 (file-notify--test-read-event))))
109 (defun file-notify--test-no-descriptors ()
110 "Check that `file-notify-descriptors' is an empty hash table.
111 Return nil when any other file notification watch is still active."
112 ;; Give read events a last chance.
113 (file-notify--wait-for-events
114 (file-notify--test-timeout)
115 (zerop (hash-table-count file-notify-descriptors)))
116 ;; Now check.
117 (zerop (hash-table-count file-notify-descriptors)))
119 (defun file-notify--test-no-descriptors-explainer ()
120 "Explain why `file-notify--test-no-descriptors' fails."
121 (let ((result (list "Watch descriptor(s) existent:")))
122 (maphash
123 (lambda (key value) (push (cons key value) result))
124 file-notify-descriptors)
125 (nreverse result)))
127 (put 'file-notify--test-no-descriptors 'ert-explainer
128 'file-notify--test-no-descriptors-explainer)
130 (defun file-notify--test-cleanup-p ()
131 "Check, that the test has cleaned up the environment as much as needed."
132 ;; `file-notify--test-event' should not be set but bound
133 ;; dynamically.
134 (should-not file-notify--test-event)
135 ;; The test should have cleaned up this already. Let's check
136 ;; nevertheless.
137 (should (file-notify--test-no-descriptors)))
139 (defun file-notify--test-cleanup ()
140 "Cleanup after a test."
141 (file-notify-rm-watch file-notify--test-desc)
142 (file-notify-rm-watch file-notify--test-desc1)
143 (file-notify-rm-watch file-notify--test-desc2)
145 (ignore-errors
146 (delete-file (file-newest-backup file-notify--test-tmpfile)))
147 (ignore-errors
148 (if (file-directory-p file-notify--test-tmpfile)
149 (delete-directory file-notify--test-tmpfile 'recursive)
150 (delete-file file-notify--test-tmpfile)))
151 (ignore-errors
152 (if (file-directory-p file-notify--test-tmpfile1)
153 (delete-directory file-notify--test-tmpfile1 'recursive)
154 (delete-file file-notify--test-tmpfile1)))
155 (ignore-errors
156 (when (file-remote-p temporary-file-directory)
157 (tramp-cleanup-connection
158 (tramp-dissect-file-name temporary-file-directory) nil 'keep-password)))
160 (when (hash-table-p file-notify-descriptors)
161 (clrhash file-notify-descriptors))
163 (setq file-notify--test-tmpfile nil
164 file-notify--test-tmpfile1 nil
165 file-notify--test-desc nil
166 file-notify--test-desc1 nil
167 file-notify--test-desc2 nil
168 file-notify--test-results nil
169 file-notify--test-events nil
170 file-notify--test-monitors nil))
172 (setq password-cache-expiry nil
173 tramp-verbose 0
174 tramp-message-show-message nil)
176 ;; This should happen on hydra only.
177 (when (getenv "EMACS_HYDRA_CI")
178 (add-to-list 'tramp-remote-path 'tramp-own-remote-path))
180 ;; We do not want to try and fail `file-notify-add-watch'.
181 (defun file-notify--test-local-enabled ()
182 "Whether local file notification is enabled.
183 This is needed for local `temporary-file-directory' only, in the
184 remote case we return always t."
185 (or file-notify--library
186 (file-remote-p temporary-file-directory)))
188 (defvar file-notify--test-remote-enabled-checked nil
189 "Cached result of `file-notify--test-remote-enabled'.
190 If the function did run, the value is a cons cell, the `cdr'
191 being the result.")
193 (defun file-notify--test-remote-enabled ()
194 "Whether remote file notification is enabled."
195 (unless (consp file-notify--test-remote-enabled-checked)
196 (let (desc)
197 (ignore-errors
198 (and
199 (file-remote-p file-notify-test-remote-temporary-file-directory)
200 (file-directory-p file-notify-test-remote-temporary-file-directory)
201 (file-writable-p file-notify-test-remote-temporary-file-directory)
202 (setq desc
203 (file-notify-add-watch
204 file-notify-test-remote-temporary-file-directory
205 '(change) #'ignore))))
206 (setq file-notify--test-remote-enabled-checked (cons t desc))
207 (when desc (file-notify-rm-watch desc))))
208 ;; Return result.
209 (cdr file-notify--test-remote-enabled-checked))
211 (defun file-notify--test-library ()
212 "The used library for the test, as a string.
213 In the remote case, it is the process name which runs on the
214 remote host, or nil."
215 (if (null (file-remote-p temporary-file-directory))
216 (symbol-name file-notify--library)
217 (and (consp file-notify--test-remote-enabled-checked)
218 (processp (cdr file-notify--test-remote-enabled-checked))
219 (replace-regexp-in-string
220 "<[[:digit:]]+>\\'" ""
221 (process-name (cdr file-notify--test-remote-enabled-checked))))))
223 (defun file-notify--test-monitor ()
224 "The used monitor for the test, as a symbol.
225 This returns only for the local case and gfilenotify; otherwise it is nil.
226 `file-notify--test-desc' must be a valid watch descriptor."
227 ;; We cache the result, because after `file-notify-rm-watch',
228 ;; `gfile-monitor-name' does not return a proper result anymore.
229 ;; But we still need this information.
230 (unless (file-remote-p temporary-file-directory)
231 (or (cdr (assq file-notify--test-desc file-notify--test-monitors))
232 (when (functionp 'gfile-monitor-name)
233 (add-to-list 'file-notify--test-monitors
234 (cons file-notify--test-desc
235 (gfile-monitor-name file-notify--test-desc)))
236 (cdr (assq file-notify--test-desc file-notify--test-monitors))))))
238 (defmacro file-notify--deftest-remote (test docstring)
239 "Define ert `TEST-remote' for remote files."
240 (declare (indent 1))
241 `(ert-deftest ,(intern (concat (symbol-name test) "-remote")) ()
242 ,docstring
243 :tags '(:expensive-test)
244 (let* ((temporary-file-directory
245 file-notify-test-remote-temporary-file-directory)
246 (ert-test (ert-get-test ',test)))
247 (skip-unless (file-notify--test-remote-enabled))
248 (tramp-cleanup-connection
249 (tramp-dissect-file-name temporary-file-directory) nil 'keep-password)
250 (funcall (ert-test-body ert-test)))))
252 (ert-deftest file-notify-test00-availability ()
253 "Test availability of `file-notify'."
254 (skip-unless (file-notify--test-local-enabled))
256 (unwind-protect
257 (progn
258 ;; Report the native library which has been used.
259 (message "Library: `%s'" (file-notify--test-library))
260 (should
261 (setq file-notify--test-desc
262 (file-notify-add-watch
263 temporary-file-directory '(change) #'ignore)))
264 (when (file-notify--test-monitor)
265 (message "Monitor: `%s'" (file-notify--test-monitor)))
266 (file-notify-rm-watch file-notify--test-desc)
268 ;; The environment shall be cleaned up.
269 (file-notify--test-cleanup-p))
271 ;; Cleanup.
272 (file-notify--test-cleanup)))
274 (file-notify--deftest-remote file-notify-test00-availability
275 "Test availability of `file-notify' for remote files.")
277 (ert-deftest file-notify-test01-add-watch ()
278 "Check `file-notify-add-watch'."
279 (skip-unless (file-notify--test-local-enabled))
281 (unwind-protect
282 (progn
283 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
284 file-notify--test-tmpfile1
285 (format
286 "%s/%s" file-notify--test-tmpfile (md5 (current-time-string))))
288 ;; Check, that different valid parameters are accepted.
289 (should
290 (setq file-notify--test-desc
291 (file-notify-add-watch
292 temporary-file-directory '(change) #'ignore)))
293 (file-notify-rm-watch file-notify--test-desc)
294 (should
295 (setq file-notify--test-desc
296 (file-notify-add-watch
297 temporary-file-directory '(attribute-change) #'ignore)))
298 (file-notify-rm-watch file-notify--test-desc)
299 (should
300 (setq file-notify--test-desc
301 (file-notify-add-watch
302 temporary-file-directory '(change attribute-change) #'ignore)))
303 (file-notify-rm-watch file-notify--test-desc)
305 ;; File monitors like kqueue insist, that the watched file
306 ;; exists. Directory monitors are not bound to this
307 ;; restriction.
308 (when (string-equal (file-notify--test-library) "kqueue")
309 (write-region
310 "any text" nil file-notify--test-tmpfile nil 'no-message))
311 (should
312 (setq file-notify--test-desc
313 (file-notify-add-watch
314 file-notify--test-tmpfile '(change attribute-change) #'ignore)))
315 (file-notify-rm-watch file-notify--test-desc)
316 (when (string-equal (file-notify--test-library) "kqueue")
317 (delete-file file-notify--test-tmpfile))
319 ;; Check error handling.
320 (should-error (file-notify-add-watch 1 2 3 4)
321 :type 'wrong-number-of-arguments)
322 (should
323 (equal (should-error
324 (file-notify-add-watch 1 2 3))
325 '(wrong-type-argument 1)))
326 (should
327 (equal (should-error
328 (file-notify-add-watch temporary-file-directory 2 3))
329 '(wrong-type-argument 2)))
330 (should
331 (equal (should-error
332 (file-notify-add-watch temporary-file-directory '(change) 3))
333 '(wrong-type-argument 3)))
334 ;; The upper directory of a file must exist.
335 (should
336 (equal (should-error
337 (file-notify-add-watch
338 file-notify--test-tmpfile1
339 '(change attribute-change) #'ignore))
340 `(file-notify-error
341 "Directory does not exist" ,file-notify--test-tmpfile)))
343 ;; The environment shall be cleaned up.
344 (file-notify--test-cleanup-p))
346 ;; Cleanup.
347 (file-notify--test-cleanup)))
349 (file-notify--deftest-remote file-notify-test01-add-watch
350 "Check `file-notify-add-watch' for remote files.")
352 (defun file-notify--test-make-temp-name ()
353 "Create a temporary file name for test."
354 (expand-file-name
355 (make-temp-name "file-notify-test") temporary-file-directory))
357 ;; This test is inspired by Bug#26126 and Bug#26127.
358 (ert-deftest file-notify-test02-rm-watch ()
359 "Check `file-notify-rm-watch'."
360 (skip-unless (file-notify--test-local-enabled))
362 (unwind-protect
363 ;; Check, that `file-notify-rm-watch' works.
364 (progn
365 (should
366 (setq file-notify--test-desc
367 (file-notify-add-watch
368 temporary-file-directory '(change) #'ignore)))
369 (file-notify-rm-watch file-notify--test-desc)
370 ;; Check, that any parameter is accepted.
371 (condition-case err
372 (progn
373 (file-notify-rm-watch nil)
374 (file-notify-rm-watch 0)
375 (file-notify-rm-watch "foo")
376 (file-notify-rm-watch 'foo))
377 (error (ert-fail err)))
379 ;; The environment shall be cleaned up.
380 (file-notify--test-cleanup-p))
382 ;; Cleanup.
383 (file-notify--test-cleanup))
385 (unwind-protect
386 ;; Check, that no error is returned removing a watch descriptor twice.
387 (progn
388 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
389 file-notify--test-tmpfile1 (file-notify--test-make-temp-name))
390 (write-region "any text" nil file-notify--test-tmpfile nil 'no-message)
391 (write-region "any text" nil file-notify--test-tmpfile1 nil 'no-message)
392 (should
393 (setq file-notify--test-desc
394 (file-notify-add-watch
395 file-notify--test-tmpfile '(change) #'ignore)))
396 (should
397 (setq file-notify--test-desc1
398 (file-notify-add-watch
399 file-notify--test-tmpfile1 '(change) #'ignore)))
400 ;; Remove `file-notify--test-desc' twice.
401 (file-notify-rm-watch file-notify--test-desc)
402 (file-notify-rm-watch file-notify--test-desc)
403 (file-notify-rm-watch file-notify--test-desc1)
404 (delete-file file-notify--test-tmpfile)
405 (delete-file file-notify--test-tmpfile1)
407 ;; The environment shall be cleaned up.
408 (file-notify--test-cleanup-p))
410 ;; Cleanup.
411 (file-notify--test-cleanup))
413 (unwind-protect
414 ;; Check, that removing watch descriptors out of order do not
415 ;; harm. This fails on Cygwin because of timing issues unless a
416 ;; long `sit-for' is added before the call to
417 ;; `file-notify--test-read-event'.
418 (if (not (eq system-type 'cygwin))
419 (let (results)
420 (cl-flet ((first-callback (event)
421 (when (eq (nth 1 event) 'deleted) (push 1 results)))
422 (second-callback (event)
423 (when (eq (nth 1 event) 'deleted) (push 2 results))))
424 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
425 (write-region
426 "any text" nil file-notify--test-tmpfile nil 'no-message)
427 (should
428 (setq file-notify--test-desc
429 (file-notify-add-watch
430 file-notify--test-tmpfile
431 '(change) #'first-callback)))
432 (should
433 (setq file-notify--test-desc1
434 (file-notify-add-watch
435 file-notify--test-tmpfile
436 '(change) #'second-callback)))
437 ;; Remove first watch.
438 (file-notify-rm-watch file-notify--test-desc)
439 ;; Only the second callback shall run.
440 (file-notify--test-read-event)
441 (delete-file file-notify--test-tmpfile)
442 (file-notify--wait-for-events
443 (file-notify--test-timeout) results)
444 (should (equal results (list 2)))
446 ;; The environment shall be cleaned up.
447 (file-notify--test-cleanup-p))))
449 ;; Cleanup.
450 (file-notify--test-cleanup)))
452 (file-notify--deftest-remote file-notify-test02-rm-watch
453 "Check `file-notify-rm-watch' for remote files.")
455 (defun file-notify--test-event-test ()
456 "Ert test function to be called by `file-notify--test-event-handler'.
457 We cannot pass arguments, so we assume that `file-notify--test-event'
458 is bound somewhere."
459 ;; Check the descriptor.
460 (should (equal (car file-notify--test-event) file-notify--test-desc))
461 ;; Check the file name.
462 (should
463 (string-prefix-p
464 (file-notify--event-watched-file file-notify--test-event)
465 (file-notify--event-file-name file-notify--test-event)))
466 ;; Check the second file name if exists.
467 (when (eq (nth 1 file-notify--test-event) 'renamed)
468 (should
469 (string-prefix-p
470 (file-notify--event-watched-file file-notify--test-event)
471 (file-notify--event-file1-name file-notify--test-event)))))
473 (defun file-notify--test-event-handler (event)
474 "Run a test over FILE-NOTIFY--TEST-EVENT.
475 For later analysis, append the test result to `file-notify--test-results'
476 and the event to `file-notify--test-events'."
477 (let* ((file-notify--test-event event)
478 (result
479 (ert-run-test (make-ert-test :body 'file-notify--test-event-test))))
480 ;; Do not add lock files, this would confuse the checks.
481 (unless (string-match
482 (regexp-quote ".#")
483 (file-notify--event-file-name file-notify--test-event))
484 ;;(message "file-notify--test-event-handler result: %s event: %S"
485 ;;(null (ert-test-failed-p result)) file-notify--test-event)
486 (setq file-notify--test-events
487 (append file-notify--test-events `(,file-notify--test-event))
488 file-notify--test-results
489 (append file-notify--test-results `(,result))))))
491 (defun file-notify--test-with-events-check (events)
492 "Check whether received events match one of the EVENTS alternatives."
493 (let (result)
494 (dolist (elt events result)
495 (setq result
496 (or result
497 (if (eq (car elt) :random)
498 (equal (sort (cdr elt) 'string-lessp)
499 (sort (mapcar #'cadr file-notify--test-events)
500 'string-lessp))
501 (equal elt (mapcar #'cadr file-notify--test-events))))))))
503 (defun file-notify--test-with-events-explainer (events)
504 "Explain why `file-notify--test-with-events-check' fails."
505 (if (null (cdr events))
506 (format "Received events do not match expected events\n%s\n%s"
507 (mapcar #'cadr file-notify--test-events) (car events))
508 (format
509 "Received events do not match any sequence of expected events\n%s\n%s"
510 (mapcar #'cadr file-notify--test-events) events)))
512 (put 'file-notify--test-with-events-check 'ert-explainer
513 'file-notify--test-with-events-explainer)
515 (defmacro file-notify--test-with-events (events &rest body)
516 "Run BODY collecting events and then compare with EVENTS.
517 EVENTS is either a simple list of events, or a list of lists of
518 events, which represent different possible results. The first
519 event of a list could be the pseudo event `:random', which is
520 just an indicator for comparison.
522 Don't wait longer than timeout seconds for the events to be
523 delivered."
524 (declare (indent 1))
525 `(let* ((events (if (consp (car ,events)) ,events (list ,events)))
526 (max-length
527 (apply
528 'max
529 (mapcar
530 (lambda (x) (length (if (eq (car x) :random) (cdr x) x)))
531 events)))
532 create-lockfiles)
533 ;; Flush pending events.
534 (file-notify--test-read-event)
535 (file-notify--wait-for-events
536 (file-notify--test-timeout)
537 (not (input-pending-p)))
538 (setq file-notify--test-events nil
539 file-notify--test-results nil)
540 ,@body
541 (file-notify--wait-for-events
542 ;; More events need more time. Use some fudge factor.
543 (* (ceiling max-length 100) (file-notify--test-timeout))
544 (= max-length (length file-notify--test-events)))
545 ;; Check the result sequence just to make sure that all events
546 ;; are as expected.
547 (dolist (result file-notify--test-results)
548 (when (ert-test-failed-p result)
549 (ert-fail
550 (cadr (ert-test-result-with-condition-condition result)))))
551 ;; One of the possible event sequences shall match.
552 (should (file-notify--test-with-events-check events))))
554 (ert-deftest file-notify-test03-events ()
555 "Check file creation/change/removal notifications."
556 (skip-unless (file-notify--test-local-enabled))
558 (unwind-protect
559 (progn
560 ;; Check file creation, change and deletion. It doesn't work
561 ;; for kqueue, because we don't use an implicit directory
562 ;; monitor.
563 (unless (string-equal (file-notify--test-library) "kqueue")
564 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
565 (should
566 (setq file-notify--test-desc
567 (file-notify-add-watch
568 file-notify--test-tmpfile
569 '(change) #'file-notify--test-event-handler)))
570 (file-notify--test-with-events
571 (cond
572 ;; gvfs-monitor-dir on cygwin does not detect the
573 ;; `created' event reliably.
574 ((string-equal
575 (file-notify--test-library) "gvfs-monitor-dir.exe")
576 '((deleted stopped)
577 (created deleted stopped)))
578 ;; cygwin does not raise a `changed' event.
579 ((eq system-type 'cygwin)
580 '(created deleted stopped))
581 (t '(created changed deleted stopped)))
582 (write-region
583 "another text" nil file-notify--test-tmpfile nil 'no-message)
584 (file-notify--test-read-event)
585 (delete-file file-notify--test-tmpfile))
586 (file-notify-rm-watch file-notify--test-desc))
588 ;; Check file change and deletion.
589 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
590 (write-region "any text" nil file-notify--test-tmpfile nil 'no-message)
591 (should
592 (setq file-notify--test-desc
593 (file-notify-add-watch
594 file-notify--test-tmpfile
595 '(change) #'file-notify--test-event-handler)))
596 (file-notify--test-with-events
597 (cond
598 ;; gvfs-monitor-dir on cygwin does not detect the
599 ;; `changed' event reliably.
600 ((string-equal (file-notify--test-library) "gvfs-monitor-dir.exe")
601 '((deleted stopped)
602 (changed deleted stopped)))
603 ;; There could be one or two `changed' events.
604 (t '((changed deleted stopped)
605 (changed changed deleted stopped))))
606 (write-region
607 "another text" nil file-notify--test-tmpfile nil 'no-message)
608 (file-notify--test-read-event)
609 (delete-file file-notify--test-tmpfile))
610 (file-notify-rm-watch file-notify--test-desc)
612 ;; Check file creation, change and deletion when watching a
613 ;; directory. There must be a `stopped' event when deleting
614 ;; the directory.
615 (let ((temporary-file-directory
616 (make-temp-file "file-notify-test-parent" t)))
617 (should
618 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
619 file-notify--test-desc
620 (file-notify-add-watch
621 temporary-file-directory
622 '(change) #'file-notify--test-event-handler)))
623 (file-notify--test-with-events
624 (cond
625 ;; w32notify does not raise `deleted' and `stopped'
626 ;; events for the watched directory.
627 ((string-equal (file-notify--test-library) "w32notify")
628 '(created changed deleted))
629 ;; gvfs-monitor-dir on cygwin does not detect the
630 ;; `created' event reliably.
631 ((string-equal
632 (file-notify--test-library) "gvfs-monitor-dir.exe")
633 '((deleted stopped)
634 (created deleted stopped)))
635 ;; There are two `deleted' events, for the file and for
636 ;; the directory. Except for cygwin and kqueue. And
637 ;; cygwin does not raise a `changed' event.
638 ((eq system-type 'cygwin)
639 '(created deleted stopped))
640 ((string-equal (file-notify--test-library) "kqueue")
641 '(created changed deleted stopped))
642 (t '(created changed deleted deleted stopped)))
643 (write-region
644 "any text" nil file-notify--test-tmpfile nil 'no-message)
645 (file-notify--test-read-event)
646 (delete-directory temporary-file-directory 'recursive))
647 (file-notify-rm-watch file-notify--test-desc))
649 ;; Check copy of files inside a directory.
650 (let ((temporary-file-directory
651 (make-temp-file "file-notify-test-parent" t)))
652 (should
653 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
654 file-notify--test-tmpfile1 (file-notify--test-make-temp-name)
655 file-notify--test-desc
656 (file-notify-add-watch
657 temporary-file-directory
658 '(change) #'file-notify--test-event-handler)))
659 (file-notify--test-with-events
660 (cond
661 ;; w32notify does not distinguish between `changed' and
662 ;; `attribute-changed'. It does not raise `deleted'
663 ;; and `stopped' events for the watched directory.
664 ((string-equal (file-notify--test-library) "w32notify")
665 '(created changed created changed
666 changed changed changed
667 deleted deleted))
668 ;; gvfs-monitor-dir on cygwin does not detect the
669 ;; `created' event reliably.
670 ((string-equal
671 (file-notify--test-library) "gvfs-monitor-dir.exe")
672 '((deleted stopped)
673 (created created deleted stopped)))
674 ;; There are three `deleted' events, for two files and
675 ;; for the directory. Except for cygwin and kqueue.
676 ((eq system-type 'cygwin)
677 '(created created changed changed deleted stopped))
678 ((string-equal (file-notify--test-library) "kqueue")
679 '(created changed created changed deleted stopped))
680 (t '(created changed created changed
681 deleted deleted deleted stopped)))
682 (write-region
683 "any text" nil file-notify--test-tmpfile nil 'no-message)
684 (file-notify--test-read-event)
685 (copy-file file-notify--test-tmpfile file-notify--test-tmpfile1)
686 ;; The next two events shall not be visible.
687 (file-notify--test-read-event)
688 (set-file-modes file-notify--test-tmpfile 000)
689 (file-notify--test-read-event)
690 (set-file-times file-notify--test-tmpfile '(0 0))
691 (file-notify--test-read-event)
692 (delete-directory temporary-file-directory 'recursive))
693 (file-notify-rm-watch file-notify--test-desc))
695 ;; Check rename of files inside a directory.
696 (let ((temporary-file-directory
697 (make-temp-file "file-notify-test-parent" t)))
698 (should
699 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
700 file-notify--test-tmpfile1 (file-notify--test-make-temp-name)
701 file-notify--test-desc
702 (file-notify-add-watch
703 temporary-file-directory
704 '(change) #'file-notify--test-event-handler)))
705 (file-notify--test-with-events
706 (cond
707 ;; w32notify does not raise `deleted' and `stopped'
708 ;; events for the watched directory.
709 ((string-equal (file-notify--test-library) "w32notify")
710 '(created changed renamed deleted))
711 ;; gvfs-monitor-dir on cygwin does not detect the
712 ;; `created' event reliably.
713 ((string-equal
714 (file-notify--test-library) "gvfs-monitor-dir.exe")
715 '((deleted stopped)
716 (created deleted stopped)))
717 ;; There are two `deleted' events, for the file and for
718 ;; the directory. Except for cygwin and kqueue. And
719 ;; cygwin raises `created' and `deleted' events instead
720 ;; of a `renamed' event.
721 ((eq system-type 'cygwin)
722 '(created created deleted deleted stopped))
723 ((string-equal (file-notify--test-library) "kqueue")
724 '(created changed renamed deleted stopped))
725 (t '(created changed renamed deleted deleted stopped)))
726 (write-region
727 "any text" nil file-notify--test-tmpfile nil 'no-message)
728 (file-notify--test-read-event)
729 (rename-file file-notify--test-tmpfile file-notify--test-tmpfile1)
730 ;; After the rename, we won't get events anymore.
731 (file-notify--test-read-event)
732 (delete-directory temporary-file-directory 'recursive))
733 (file-notify-rm-watch file-notify--test-desc))
735 ;; Check attribute change. Does not work for cygwin.
736 (unless (eq system-type 'cygwin)
737 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
738 (write-region
739 "any text" nil file-notify--test-tmpfile nil 'no-message)
740 (should
741 (setq file-notify--test-desc
742 (file-notify-add-watch
743 file-notify--test-tmpfile
744 '(attribute-change) #'file-notify--test-event-handler)))
745 (file-notify--test-with-events
746 (cond
747 ;; w32notify does not distinguish between `changed' and
748 ;; `attribute-changed'. Under MS Windows 7, we get
749 ;; four `changed' events, and under MS Windows 10 just
750 ;; two. Strange.
751 ((string-equal (file-notify--test-library) "w32notify")
752 '((changed changed)
753 (changed changed changed changed)))
754 ;; For kqueue and in the remote case, `write-region'
755 ;; raises also an `attribute-changed' event.
756 ((or (string-equal (file-notify--test-library) "kqueue")
757 (file-remote-p temporary-file-directory))
758 '(attribute-changed attribute-changed attribute-changed))
759 (t '(attribute-changed attribute-changed)))
760 (write-region
761 "any text" nil file-notify--test-tmpfile nil 'no-message)
762 (file-notify--test-read-event)
763 (set-file-modes file-notify--test-tmpfile 000)
764 (file-notify--test-read-event)
765 (set-file-times file-notify--test-tmpfile '(0 0))
766 (file-notify--test-read-event)
767 (delete-file file-notify--test-tmpfile))
768 (file-notify-rm-watch file-notify--test-desc))
770 ;; The environment shall be cleaned up.
771 (file-notify--test-cleanup-p))
773 ;; Cleanup.
774 (file-notify--test-cleanup)))
776 (file-notify--deftest-remote file-notify-test03-events
777 "Check file creation/change/removal notifications for remote files.")
779 (require 'autorevert)
780 (setq auto-revert-notify-exclude-dir-regexp "nothing-to-be-excluded"
781 auto-revert-remote-files t
782 auto-revert-stop-on-user-input nil)
784 (ert-deftest file-notify-test04-autorevert ()
785 "Check autorevert via file notification."
786 (skip-unless (file-notify--test-local-enabled))
788 ;; `auto-revert-buffers' runs every 5". And we must wait, until the
789 ;; file has been reverted.
790 (let ((timeout (if (file-remote-p temporary-file-directory) 60 10))
791 buf)
792 (unwind-protect
793 (progn
794 ;; In the remote case, `vc-refresh-state' returns undesired
795 ;; error messages. Let's suppress them.
796 (advice-add 'vc-refresh-state :around 'ignore)
797 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
798 (write-region
799 "any text" nil file-notify--test-tmpfile nil 'no-message)
800 (setq buf (find-file-noselect file-notify--test-tmpfile))
801 (with-current-buffer buf
802 (should (string-equal (buffer-string) "any text"))
803 ;; `buffer-stale--default-function' checks for
804 ;; `verify-visited-file-modtime'. We must ensure that it
805 ;; returns nil.
806 (sleep-for 1)
807 (auto-revert-mode 1)
809 ;; `auto-revert-buffers' runs every 5".
810 (with-timeout (timeout (ignore))
811 (while (null auto-revert-notify-watch-descriptor)
812 (sleep-for 1)))
814 ;; `file-notify--test-monitor' needs to know
815 ;; `file-notify--test-desc' in order to compute proper
816 ;; timeouts.
817 (setq file-notify--test-desc auto-revert-notify-watch-descriptor)
819 ;; Check, that file notification has been used.
820 (should auto-revert-mode)
821 (should auto-revert-use-notify)
822 (should auto-revert-notify-watch-descriptor)
824 ;; Modify file. We wait for a second, in order to have
825 ;; another timestamp.
826 (ert-with-message-capture captured-messages
827 (sleep-for 1)
828 (write-region
829 "another text" nil file-notify--test-tmpfile nil 'no-message)
831 ;; Check, that the buffer has been reverted.
832 (file-notify--wait-for-events
833 timeout
834 (string-match
835 (format-message "Reverting buffer `%s'." (buffer-name buf))
836 captured-messages))
837 (should (string-match "another text" (buffer-string))))
839 ;; Stop file notification. Autorevert shall still work via polling.
840 (file-notify-rm-watch auto-revert-notify-watch-descriptor)
841 (file-notify--wait-for-events
842 timeout (null auto-revert-use-notify))
843 (should-not auto-revert-use-notify)
844 (should-not auto-revert-notify-watch-descriptor)
846 ;; Modify file. We wait for two seconds, in order to
847 ;; have another timestamp. One second seems to be too
848 ;; short.
849 (ert-with-message-capture captured-messages
850 (sleep-for 2)
851 (write-region
852 "foo bla" nil file-notify--test-tmpfile nil 'no-message)
854 ;; Check, that the buffer has been reverted.
855 (file-notify--wait-for-events
856 timeout
857 (string-match
858 (format-message "Reverting buffer `%s'." (buffer-name buf))
859 captured-messages))
860 (should (string-match "foo bla" (buffer-string)))))
862 ;; The environment shall be cleaned up.
863 (file-notify--test-cleanup-p))
865 ;; Cleanup.
866 (advice-remove 'vc-refresh-state 'ignore)
867 (ignore-errors (kill-buffer buf))
868 (file-notify--test-cleanup))))
870 (file-notify--deftest-remote file-notify-test04-autorevert
871 "Check autorevert via file notification for remote files.")
873 (ert-deftest file-notify-test05-file-validity ()
874 "Check `file-notify-valid-p' for files."
875 (skip-unless (file-notify--test-local-enabled))
877 (unwind-protect
878 (progn
879 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
880 (write-region "any text" nil file-notify--test-tmpfile nil 'no-message)
881 (should
882 (setq file-notify--test-desc
883 (file-notify-add-watch
884 file-notify--test-tmpfile '(change) #'ignore)))
885 (should (file-notify-valid-p file-notify--test-desc))
886 ;; After calling `file-notify-rm-watch', the descriptor is not
887 ;; valid anymore.
888 (file-notify-rm-watch file-notify--test-desc)
889 (should-not (file-notify-valid-p file-notify--test-desc))
890 (delete-file file-notify--test-tmpfile)
892 ;; The environment shall be cleaned up.
893 (file-notify--test-cleanup-p))
895 ;; Cleanup.
896 (file-notify--test-cleanup))
898 (unwind-protect
899 (progn
900 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
901 (write-region "any text" nil file-notify--test-tmpfile nil 'no-message)
902 (should
903 (setq file-notify--test-desc
904 (file-notify-add-watch
905 file-notify--test-tmpfile
906 '(change) #'file-notify--test-event-handler)))
907 (should (file-notify-valid-p file-notify--test-desc))
908 (file-notify--test-with-events
909 (cond
910 ;; gvfs-monitor-dir on cygwin does not detect the
911 ;; `changed' event reliably.
912 ((string-equal (file-notify--test-library) "gvfs-monitor-dir.exe")
913 '((deleted stopped)
914 (changed deleted stopped)))
915 ;; There could be one or two `changed' events.
916 (t '((changed deleted stopped)
917 (changed changed deleted stopped))))
918 (write-region
919 "another text" nil file-notify--test-tmpfile nil 'no-message)
920 (file-notify--test-read-event)
921 (delete-file file-notify--test-tmpfile))
922 ;; After deleting the file, the descriptor is not valid anymore.
923 (should-not (file-notify-valid-p file-notify--test-desc))
924 (file-notify-rm-watch file-notify--test-desc)
926 ;; The environment shall be cleaned up.
927 (file-notify--test-cleanup-p))
929 ;; Cleanup.
930 (file-notify--test-cleanup))
932 (unwind-protect
933 (let ((temporary-file-directory
934 (make-temp-file "file-notify-test-parent" t)))
935 (should
936 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
937 file-notify--test-desc
938 (file-notify-add-watch
939 temporary-file-directory
940 '(change) #'file-notify--test-event-handler)))
941 (should (file-notify-valid-p file-notify--test-desc))
942 (file-notify--test-with-events
943 (cond
944 ;; w32notify does not raise `deleted' and `stopped' events
945 ;; for the watched directory.
946 ((string-equal (file-notify--test-library) "w32notify")
947 '(created changed deleted))
948 ;; gvfs-monitor-dir on cygwin does not detect the `created'
949 ;; event reliably.
950 ((string-equal (file-notify--test-library) "gvfs-monitor-dir.exe")
951 '((deleted stopped)
952 (created deleted stopped)))
953 ;; There are two `deleted' events, for the file and for the
954 ;; directory. Except for cygwin and kqueue. And cygwin
955 ;; does not raise a `changed' event.
956 ((eq system-type 'cygwin)
957 '(created deleted stopped))
958 ((string-equal (file-notify--test-library) "kqueue")
959 '(created changed deleted stopped))
960 (t '(created changed deleted deleted stopped)))
961 (write-region
962 "any text" nil file-notify--test-tmpfile nil 'no-message)
963 (file-notify--test-read-event)
964 (delete-directory temporary-file-directory t))
965 ;; After deleting the parent directory, the descriptor must
966 ;; not be valid anymore.
967 (should-not (file-notify-valid-p file-notify--test-desc))
968 ;; w32notify doesn't generate `stopped' events when the parent
969 ;; directory is deleted, which doesn't provide a chance for
970 ;; filenotify.el to remove the descriptor from the internal
971 ;; hash table it maintains. So we must remove the descriptor
972 ;; manually.
973 (if (string-equal (file-notify--test-library) "w32notify")
974 (file-notify--rm-descriptor file-notify--test-desc))
976 ;; The environment shall be cleaned up.
977 (file-notify--test-cleanup-p))
979 ;; Cleanup.
980 (file-notify--test-cleanup)))
982 (file-notify--deftest-remote file-notify-test05-file-validity
983 "Check `file-notify-valid-p' via file notification for remote files.")
985 (ert-deftest file-notify-test06-dir-validity ()
986 "Check `file-notify-valid-p' for directories."
987 (skip-unless (file-notify--test-local-enabled))
989 (unwind-protect
990 (progn
991 (should
992 (setq file-notify--test-tmpfile
993 (make-temp-file "file-notify-test-parent" t)))
994 (should
995 (setq file-notify--test-desc
996 (file-notify-add-watch
997 file-notify--test-tmpfile '(change) #'ignore)))
998 (should (file-notify-valid-p file-notify--test-desc))
999 ;; After removing the watch, the descriptor must not be valid
1000 ;; anymore.
1001 (file-notify-rm-watch file-notify--test-desc)
1002 (file-notify--wait-for-events
1003 (file-notify--test-timeout)
1004 (not (file-notify-valid-p file-notify--test-desc)))
1005 (should-not (file-notify-valid-p file-notify--test-desc))
1006 (delete-directory file-notify--test-tmpfile t)
1008 ;; The environment shall be cleaned up.
1009 (file-notify--test-cleanup-p))
1011 ;; Cleanup.
1012 (file-notify--test-cleanup))
1014 (unwind-protect
1015 (progn
1016 (should
1017 (setq file-notify--test-tmpfile
1018 (make-temp-file "file-notify-test-parent" t)))
1019 (should
1020 (setq file-notify--test-desc
1021 (file-notify-add-watch
1022 file-notify--test-tmpfile '(change) #'ignore)))
1023 (should (file-notify-valid-p file-notify--test-desc))
1024 ;; After deleting the directory, the descriptor must not be
1025 ;; valid anymore.
1026 (delete-directory file-notify--test-tmpfile t)
1027 (file-notify--wait-for-events
1028 (file-notify--test-timeout)
1029 (not (file-notify-valid-p file-notify--test-desc)))
1030 (should-not (file-notify-valid-p file-notify--test-desc))
1031 (if (string-equal (file-notify--test-library) "w32notify")
1032 (file-notify--rm-descriptor file-notify--test-desc))
1034 ;; The environment shall be cleaned up.
1035 (file-notify--test-cleanup-p))
1037 ;; Cleanup.
1038 (file-notify--test-cleanup)))
1040 (file-notify--deftest-remote file-notify-test06-dir-validity
1041 "Check `file-notify-valid-p' via file notification for remote directories.")
1043 (ert-deftest file-notify-test07-many-events ()
1044 "Check that events are not dropped."
1045 :tags '(:expensive-test)
1046 (skip-unless (file-notify--test-local-enabled))
1048 (should
1049 (setq file-notify--test-tmpfile
1050 (make-temp-file "file-notify-test-parent" t)))
1051 (should
1052 (setq file-notify--test-desc
1053 (file-notify-add-watch
1054 file-notify--test-tmpfile
1055 '(change) #'file-notify--test-event-handler)))
1056 (unwind-protect
1057 (let ((n 1000)
1058 source-file-list target-file-list
1059 (default-directory file-notify--test-tmpfile))
1060 (dotimes (i n)
1061 ;; It matters which direction we rename, at least for
1062 ;; kqueue. This backend parses directories in alphabetic
1063 ;; order (x%d before y%d). So we rename into both directions.
1064 (if (zerop (mod i 2))
1065 (progn
1066 (push (expand-file-name (format "x%d" i)) source-file-list)
1067 (push (expand-file-name (format "y%d" i)) target-file-list))
1068 (push (expand-file-name (format "y%d" i)) source-file-list)
1069 (push (expand-file-name (format "x%d" i)) target-file-list)))
1070 (file-notify--test-with-events (make-list (+ n n) 'created)
1071 (let ((source-file-list source-file-list)
1072 (target-file-list target-file-list))
1073 (while (and source-file-list target-file-list)
1074 (file-notify--test-read-event)
1075 (write-region "" nil (pop source-file-list) nil 'no-message)
1076 (file-notify--test-read-event)
1077 (write-region "" nil (pop target-file-list) nil 'no-message))))
1078 (file-notify--test-with-events
1079 (cond
1080 ;; w32notify fires both `deleted' and `renamed' events.
1081 ((string-equal (file-notify--test-library) "w32notify")
1082 (let (r)
1083 (dotimes (_i n r)
1084 (setq r (append '(deleted renamed) r)))))
1085 ;; cygwin fires `changed' and `deleted' events, sometimes
1086 ;; in random order.
1087 ((eq system-type 'cygwin)
1088 (let (r)
1089 (dotimes (_i n (cons :random r))
1090 (setq r (append '(changed deleted) r)))))
1091 (t (make-list n 'renamed)))
1092 (let ((source-file-list source-file-list)
1093 (target-file-list target-file-list))
1094 (while (and source-file-list target-file-list)
1095 (file-notify--test-read-event)
1096 (rename-file (pop source-file-list) (pop target-file-list) t))))
1097 (file-notify--test-with-events (make-list n 'deleted)
1098 (dolist (file target-file-list)
1099 (file-notify--test-read-event)
1100 (delete-file file)))
1101 (delete-directory file-notify--test-tmpfile)
1102 (if (string-equal (file-notify--test-library) "w32notify")
1103 (file-notify--rm-descriptor file-notify--test-desc))
1105 ;; The environment shall be cleaned up.
1106 (file-notify--test-cleanup-p))
1108 ;; Cleanup.
1109 (file-notify--test-cleanup)))
1111 (file-notify--deftest-remote file-notify-test07-many-events
1112 "Check that events are not dropped for remote directories.")
1114 (ert-deftest file-notify-test08-backup ()
1115 "Check that backup keeps file notification."
1116 (skip-unless (file-notify--test-local-enabled))
1118 (unwind-protect
1119 (progn
1120 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
1121 (write-region "any text" nil file-notify--test-tmpfile nil 'no-message)
1122 (should
1123 (setq file-notify--test-desc
1124 (file-notify-add-watch
1125 file-notify--test-tmpfile
1126 '(change) #'file-notify--test-event-handler)))
1127 (should (file-notify-valid-p file-notify--test-desc))
1128 (file-notify--test-with-events
1129 ;; There could be one or two `changed' events.
1130 '((changed)
1131 (changed changed))
1132 ;; There shouldn't be any problem, because the file is kept.
1133 (with-temp-buffer
1134 (let ((buffer-file-name file-notify--test-tmpfile)
1135 (make-backup-files t)
1136 (backup-by-copying t)
1137 (kept-new-versions 1)
1138 (delete-old-versions t))
1139 (insert "another text")
1140 (save-buffer))))
1141 ;; After saving the buffer, the descriptor is still valid.
1142 (should (file-notify-valid-p file-notify--test-desc))
1143 (delete-file file-notify--test-tmpfile)
1145 ;; The environment shall be cleaned up.
1146 (file-notify--test-cleanup-p))
1148 ;; Cleanup.
1149 (file-notify--test-cleanup))
1151 (unwind-protect
1152 ;; It doesn't work for kqueue, because we don't use an implicit
1153 ;; directory monitor.
1154 (unless (string-equal (file-notify--test-library) "kqueue")
1155 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
1156 (write-region
1157 "any text" nil file-notify--test-tmpfile nil 'no-message)
1158 (should
1159 (setq file-notify--test-desc
1160 (file-notify-add-watch
1161 file-notify--test-tmpfile
1162 '(change) #'file-notify--test-event-handler)))
1163 (should (file-notify-valid-p file-notify--test-desc))
1164 (file-notify--test-with-events
1165 (cond
1166 ;; On cygwin we only get the `changed' event.
1167 ((eq system-type 'cygwin) '(changed))
1168 (t '(renamed created changed)))
1169 ;; The file is renamed when creating a backup. It shall
1170 ;; still be watched.
1171 (with-temp-buffer
1172 (let ((buffer-file-name file-notify--test-tmpfile)
1173 (make-backup-files t)
1174 (backup-by-copying nil)
1175 (backup-by-copying-when-mismatch nil)
1176 (kept-new-versions 1)
1177 (delete-old-versions t))
1178 (insert "another text")
1179 (save-buffer))))
1180 ;; After saving the buffer, the descriptor is still valid.
1181 (should (file-notify-valid-p file-notify--test-desc))
1182 (delete-file file-notify--test-tmpfile)
1184 ;; The environment shall be cleaned up.
1185 (file-notify--test-cleanup-p))
1187 ;; Cleanup.
1188 (file-notify--test-cleanup)))
1190 (file-notify--deftest-remote file-notify-test08-backup
1191 "Check that backup keeps file notification for remote files.")
1193 (ert-deftest file-notify-test09-watched-file-in-watched-dir ()
1194 "Watches a directory and a file in that directory separately.
1195 Checks that the callbacks are only called with events with
1196 descriptors that were issued when registering the watches. This
1197 test caters for the situation in bug#22736 where the callback for
1198 the directory received events for the file with the descriptor of
1199 the file watch."
1200 :tags '(:expensive-test)
1201 (skip-unless (file-notify--test-local-enabled))
1203 ;; A directory to be watched.
1204 (should
1205 (setq file-notify--test-tmpfile
1206 (make-temp-file "file-notify-test-parent" t)))
1207 ;; A file to be watched.
1208 (should
1209 (setq file-notify--test-tmpfile1
1210 (let ((temporary-file-directory file-notify--test-tmpfile))
1211 (file-notify--test-make-temp-name))))
1212 (write-region "any text" nil file-notify--test-tmpfile1 nil 'no-message)
1213 (unwind-protect
1214 (cl-flet (;; Directory monitor.
1215 (dir-callback (event)
1216 (let ((file-notify--test-desc file-notify--test-desc1))
1217 (file-notify--test-event-handler event)))
1218 ;; File monitor.
1219 (file-callback (event)
1220 (let ((file-notify--test-desc file-notify--test-desc2))
1221 (file-notify--test-event-handler event))))
1222 (should
1223 (setq file-notify--test-desc1
1224 (file-notify-add-watch
1225 file-notify--test-tmpfile
1226 '(change) #'dir-callback)
1227 ;; This is needed for `file-notify--test-monitor'.
1228 file-notify--test-desc file-notify--test-desc1))
1229 (should
1230 (setq file-notify--test-desc2
1231 (file-notify-add-watch
1232 file-notify--test-tmpfile1
1233 '(change) #'file-callback)))
1234 (should (file-notify-valid-p file-notify--test-desc1))
1235 (should (file-notify-valid-p file-notify--test-desc2))
1236 (should-not (equal file-notify--test-desc1 file-notify--test-desc2))
1237 (let ((n 100))
1238 ;; Run the test.
1239 (file-notify--test-with-events
1240 ;; There could be one or two `changed' events.
1241 (list
1242 ;; cygwin.
1243 (append
1244 '(:random)
1245 (make-list (/ n 2) 'changed)
1246 (make-list (/ n 2) 'created)
1247 (make-list (/ n 2) 'changed))
1248 (append
1249 '(:random)
1250 ;; Directory monitor and file monitor.
1251 (make-list (/ n 2) 'changed)
1252 (make-list (/ n 2) 'changed)
1253 ;; Just the directory monitor.
1254 (make-list (/ n 2) 'created)
1255 (make-list (/ n 2) 'changed))
1256 (append
1257 '(:random)
1258 ;; Directory monitor and file monitor.
1259 (make-list (/ n 2) 'changed)
1260 (make-list (/ n 2) 'changed)
1261 (make-list (/ n 2) 'changed)
1262 (make-list (/ n 2) 'changed)
1263 ;; Just the directory monitor.
1264 (make-list (/ n 2) 'created)
1265 (make-list (/ n 2) 'changed)))
1266 (dotimes (i n)
1267 (file-notify--test-read-event)
1268 (if (zerop (mod i 2))
1269 (write-region
1270 "any text" nil file-notify--test-tmpfile1 t 'no-message)
1271 (let ((temporary-file-directory file-notify--test-tmpfile))
1272 (write-region
1273 "any text" nil
1274 (file-notify--test-make-temp-name) nil 'no-message))))))
1276 ;; If we delete the file, the directory monitor shall still be
1277 ;; active. We receive the `deleted' event from both the
1278 ;; directory and the file monitor. The `stopped' event is
1279 ;; from the file monitor. It's undecided in which order the
1280 ;; the directory and the file monitor are triggered.
1281 (file-notify--test-with-events '(:random deleted deleted stopped)
1282 (delete-file file-notify--test-tmpfile1))
1283 (should (file-notify-valid-p file-notify--test-desc1))
1284 (should-not (file-notify-valid-p file-notify--test-desc2))
1286 ;; Now we delete the directory.
1287 (file-notify--test-with-events
1288 (cond
1289 ;; In kqueue and for cygwin, just one `deleted' event for
1290 ;; the directory is received.
1291 ((or (eq system-type 'cygwin)
1292 (string-equal (file-notify--test-library) "kqueue"))
1293 '(deleted stopped))
1294 (t (append
1295 ;; The directory monitor raises a `deleted' event for
1296 ;; every file contained in the directory, we must
1297 ;; count them.
1298 (make-list
1299 (length
1300 (directory-files
1301 file-notify--test-tmpfile nil
1302 directory-files-no-dot-files-regexp 'nosort))
1303 'deleted)
1304 ;; The events of the directory itself.
1305 (cond
1306 ;; w32notify does not raise `deleted' and `stopped'
1307 ;; events for the watched directory.
1308 ((string-equal (file-notify--test-library) "w32notify") '())
1309 (t '(deleted stopped))))))
1310 (delete-directory file-notify--test-tmpfile 'recursive))
1311 (should-not (file-notify-valid-p file-notify--test-desc1))
1312 (should-not (file-notify-valid-p file-notify--test-desc2))
1313 (when (string-equal (file-notify--test-library) "w32notify")
1314 (file-notify--rm-descriptor file-notify--test-desc1)
1315 (file-notify--rm-descriptor file-notify--test-desc2))
1317 ;; The environment shall be cleaned up.
1318 (file-notify--test-cleanup-p))
1320 ;; Cleanup.
1321 (file-notify--test-cleanup)))
1323 ;(file-notify--deftest-remote file-notify-test09-watched-file-in-watched-dir
1324 ; "Check `file-notify-test09-watched-file-in-watched-dir' for remote files.")
1326 (ert-deftest file-notify-test10-sufficient-resources ()
1327 "Check that file notification does not use too many resources."
1328 :tags '(:expensive-test)
1329 (skip-unless (file-notify--test-local-enabled))
1330 ;; This test is intended for kqueue only.
1331 (skip-unless (string-equal (file-notify--test-library) "kqueue"))
1333 (should
1334 (setq file-notify--test-tmpfile
1335 (make-temp-file "file-notify-test-parent" t)))
1336 (unwind-protect
1337 (let ((temporary-file-directory file-notify--test-tmpfile)
1338 descs)
1339 (should-error
1340 (while t
1341 ;; We watch directories, because we want to reach the upper
1342 ;; limit. Watching a file might not be sufficient, because
1343 ;; most of the libraries implement this as watching the
1344 ;; upper directory.
1345 (setq file-notify--test-tmpfile1
1346 (make-temp-file "file-notify-test-parent" t)
1347 descs
1348 (cons
1349 (should
1350 (file-notify-add-watch
1351 file-notify--test-tmpfile1 '(change) #'ignore))
1352 descs)))
1353 :type 'file-notify-error)
1354 ;; Remove watches. If we don't do it prior removing
1355 ;; directories, Emacs crashes in batch mode.
1356 (dolist (desc descs)
1357 (file-notify-rm-watch desc))
1358 ;; Remove directories.
1359 (delete-directory file-notify--test-tmpfile 'recursive)
1361 ;; The environment shall be cleaned up.
1362 (file-notify--test-cleanup-p))
1364 ;; Cleanup.
1365 (file-notify--test-cleanup)))
1367 (file-notify--deftest-remote file-notify-test10-sufficient-resources
1368 "Check `file-notify-test10-sufficient-resources' for remote files.")
1370 (defun file-notify-test-all (&optional interactive)
1371 "Run all tests for \\[file-notify]."
1372 (interactive "p")
1373 (if interactive
1374 (ert-run-tests-interactively "^file-notify-")
1375 (ert-run-tests-batch "^file-notify-")))
1377 ;; TODO:
1379 ;; * kqueue does not send all expected `deleted' events. Maybe due to
1380 ;; the missing directory monitor.
1381 ;; * For w32notify, no `deleted' and `stopped' events arrive when a
1382 ;; directory is removed.
1383 ;; * For cygwin and w32notify, no `attribute-changed' events arrive.
1384 ;; They send `changed' events instead.
1385 ;; * cygwin does not send all expected `changed' and `deleted' events.
1386 ;; Probably due to timing issues.
1388 (provide 'file-notify-tests)
1389 ;;; filenotify-tests.el ends here