Commit | Line | Data |
---|---|---|
46e4f821 MA |
1 | ;;; file-notify-tests.el --- Tests of file notifications |
2 | ||
ba318903 | 3 | ;; Copyright (C) 2013-2014 Free Software Foundation, Inc. |
46e4f821 MA |
4 | |
5 | ;; Author: Michael Albinus <michael.albinus@gmx.de> | |
6 | ||
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. | |
11 | ;; | |
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. | |
16 | ;; | |
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/'. | |
19 | ||
20 | ;;; Commentary: | |
21 | ||
1baa1e49 MA |
22 | ;; Some of the tests require access to a remote host files. Set |
23 | ;; $REMOTE_TEMPORARY_FILE_DIRECTORY to a suitable value in order | |
24 | ;; to overwrite the default value. If you want to skip tests | |
25 | ;; accessing a remote host, set this environment variable to | |
26 | ;; "/dev/null" or whatever is appropriate on your system. | |
84b6d3df | 27 | |
1baa1e49 MA |
28 | ;; When running the tests in batch mode, it must NOT require an |
29 | ;; interactive password prompt unless the environment variable | |
30 | ;; $REMOTE_ALLOW_PASSWORD is set. | |
31 | ||
32 | ;; A whole test run can be performed calling the command `file-notify-test-all'. | |
46e4f821 MA |
33 | |
34 | ;;; Code: | |
35 | ||
36 | (require 'ert) | |
37 | (require 'filenotify) | |
38 | ||
84b6d3df MA |
39 | ;; There is no default value on w32 systems, which could work out of the box. |
40 | (defconst file-notify-test-remote-temporary-file-directory | |
1baa1e49 MA |
41 | (cond |
42 | ((getenv "REMOTE_TEMPORARY_FILE_DIRECTORY")) | |
43 | ((eq system-type 'windows-nt) null-device) | |
44 | (t (format "/ssh::%s" temporary-file-directory))) | |
84b6d3df MA |
45 | "Temporary directory for Tramp tests.") |
46 | ||
47 | (defvar file-notify--test-tmpfile nil) | |
48 | (defvar file-notify--test-tmpfile1 nil) | |
49 | (defvar file-notify--test-results nil) | |
50 | (defvar file-notify--test-event nil) | |
51 | ||
52 | (require 'tramp) | |
53 | (setq tramp-verbose 0 | |
54 | tramp-message-show-message nil) | |
1baa1e49 MA |
55 | |
56 | ;; Disable interactive passwords in batch mode. | |
57 | (when (and noninteractive (not (getenv "REMOTE_ALLOW_PASSWORD"))) | |
58 | (defalias 'tramp-read-passwd 'ignore)) | |
59 | ||
1c49d6c2 MA |
60 | ;; This shall happen on hydra only. |
61 | (when (getenv "NIX_STORE") | |
62 | (add-to-list 'tramp-remote-path 'tramp-own-remote-path)) | |
84b6d3df | 63 | |
e81dd54d | 64 | ;; We do not want to try and fail `file-notify-add-watch'. |
4ddbf128 MA |
65 | (defun file-notify--test-local-enabled () |
66 | "Whether local file notification is enabled. | |
67 | This is needed for local `temporary-file-directory' only, in the | |
68 | remote case we return always `t'." | |
69 | (or file-notify--library | |
63389c25 | 70 | (file-remote-p temporary-file-directory))) |
4ddbf128 MA |
71 | |
72 | (defvar file-notify--test-remote-enabled-checked nil | |
73 | "Cached result of `file-notify--test-remote-enabled'. | |
74 | If the function did run, the value is a cons cell, the `cdr' | |
75 | being the result.") | |
e81dd54d | 76 | |
e81dd54d MA |
77 | (defun file-notify--test-remote-enabled () |
78 | "Whether remote file notification is enabled." | |
4ddbf128 MA |
79 | (unless (consp file-notify--test-remote-enabled-checked) |
80 | (let (desc) | |
81 | (unwind-protect | |
82 | (ignore-errors | |
83 | (and | |
84 | (file-remote-p file-notify-test-remote-temporary-file-directory) | |
85 | (file-directory-p file-notify-test-remote-temporary-file-directory) | |
86 | (file-writable-p file-notify-test-remote-temporary-file-directory) | |
87 | (setq desc | |
88 | (file-notify-add-watch | |
89 | file-notify-test-remote-temporary-file-directory | |
90 | '(change) 'ignore)))) | |
91 | ;; Unwind forms. | |
92 | (setq file-notify--test-remote-enabled-checked (cons t desc)) | |
93 | (when desc (file-notify-rm-watch desc))))) | |
94 | ;; Return result. | |
95 | (cdr file-notify--test-remote-enabled-checked)) | |
e81dd54d | 96 | |
84b6d3df MA |
97 | (defmacro file-notify--deftest-remote (test docstring) |
98 | "Define ert `TEST-remote' for remote files." | |
4ddbf128 MA |
99 | `(ert-deftest ,(intern (concat (symbol-name test) "-remote")) () |
100 | ,docstring | |
101 | (let* ((temporary-file-directory | |
102 | file-notify-test-remote-temporary-file-directory) | |
103 | (ert-test (ert-get-test ',test))) | |
104 | (skip-unless (file-notify--test-remote-enabled)) | |
1baa1e49 MA |
105 | (tramp-cleanup-connection |
106 | (tramp-dissect-file-name temporary-file-directory) nil 'keep-password) | |
4ddbf128 | 107 | (funcall (ert-test-body ert-test))))) |
84b6d3df MA |
108 | |
109 | (ert-deftest file-notify-test00-availability () | |
110 | "Test availability of `file-notify'." | |
4ddbf128 | 111 | (skip-unless (file-notify--test-local-enabled)) |
e81dd54d MA |
112 | (let (desc) |
113 | ;; Check, that different valid parameters are accepted. | |
114 | (should (setq desc (file-notify-add-watch | |
115 | temporary-file-directory '(change) 'ignore))) | |
116 | (file-notify-rm-watch desc))) | |
117 | ||
118 | (file-notify--deftest-remote file-notify-test00-availability | |
119 | "Test availability of `file-notify' for remote files.") | |
46e4f821 | 120 | |
4ddbf128 MA |
121 | (ert-deftest file-notify-test01-add-watch () |
122 | "Check `file-notify-add-watch'." | |
123 | (skip-unless (file-notify--test-local-enabled)) | |
124 | (let (desc) | |
125 | ;; Check, that different valid parameters are accepted. | |
126 | (should (setq desc (file-notify-add-watch | |
127 | temporary-file-directory '(change) 'ignore))) | |
128 | (file-notify-rm-watch desc) | |
129 | (should (setq desc (file-notify-add-watch | |
130 | temporary-file-directory | |
131 | '(attribute-change) 'ignore))) | |
132 | (file-notify-rm-watch desc) | |
133 | (should (setq desc (file-notify-add-watch | |
134 | temporary-file-directory | |
135 | '(change attribute-change) 'ignore))) | |
136 | (file-notify-rm-watch desc) | |
46e4f821 | 137 | |
4ddbf128 MA |
138 | ;; Check error handling. |
139 | (should-error (file-notify-add-watch 1 2 3 4) | |
140 | :type 'wrong-number-of-arguments) | |
141 | (should | |
142 | (equal (should-error (file-notify-add-watch 1 2 3)) | |
143 | '(wrong-type-argument 1))) | |
144 | (should | |
145 | (equal (should-error (file-notify-add-watch | |
146 | temporary-file-directory 2 3)) | |
147 | '(wrong-type-argument 2))) | |
148 | (should | |
149 | (equal (should-error (file-notify-add-watch | |
150 | temporary-file-directory '(change) 3)) | |
151 | '(wrong-type-argument 3))))) | |
59eb37e5 | 152 | |
4ddbf128 MA |
153 | (file-notify--deftest-remote file-notify-test01-add-watch |
154 | "Check `file-notify-add-watch' for remote files.") | |
46e4f821 | 155 | |
84b6d3df MA |
156 | (defun file-notify--test-event-test () |
157 | "Ert test function to be called by `file-notify--test-event-handler'. | |
158 | We cannot pass arguments, so we assume that `file-notify--test-event' | |
46e4f821 | 159 | is bound somewhere." |
84b6d3df | 160 | ;(message "Event %S" file-notify--test-event) |
46e4f821 MA |
161 | ;; Check the file name. |
162 | (should | |
84b6d3df MA |
163 | (string-equal (file-notify--event-file-name file-notify--test-event) |
164 | file-notify--test-tmpfile)) | |
46e4f821 | 165 | ;; Check the second file name if exists. |
84b6d3df | 166 | (when (eq (nth 1 file-notify--test-event) 'renamed) |
46e4f821 MA |
167 | (should |
168 | (string-equal | |
84b6d3df MA |
169 | (file-notify--event-file1-name file-notify--test-event) |
170 | file-notify--test-tmpfile1)))) | |
171 | ||
172 | (defun file-notify--test-event-handler (file-notify--test-event) | |
173 | "Run a test over FILE-NOTIFY--TEST-EVENT. | |
174 | Save the result in `file-notify--test-results', for later analysis." | |
175 | (let ((result | |
176 | (ert-run-test (make-ert-test :body 'file-notify--test-event-test)))) | |
177 | (setq file-notify--test-results | |
178 | (append file-notify--test-results `(,result))))) | |
179 | ||
180 | (defun file-notify--test-make-temp-name () | |
46e4f821 MA |
181 | "Create a temporary file name for test." |
182 | (expand-file-name | |
183 | (make-temp-name "file-notify-test") temporary-file-directory)) | |
184 | ||
63389c25 MA |
185 | (defmacro file-notify--wait-for-events (timeout until) |
186 | "Wait for file notification events until form UNTIL is true. | |
dc9c8c62 | 187 | TIMEOUT is the maximum time to wait for, in seconds." |
63389c25 MA |
188 | `(with-timeout (,timeout (ignore)) |
189 | (while (null ,until) | |
40d2f2e4 | 190 | (read-event nil nil 0.1)))) |
63389c25 | 191 | |
4ddbf128 MA |
192 | (ert-deftest file-notify-test02-events () |
193 | "Check file creation/removal notifications." | |
194 | (skip-unless (file-notify--test-local-enabled)) | |
195 | (let (desc) | |
196 | (unwind-protect | |
197 | (progn | |
198 | (setq file-notify--test-results nil | |
199 | file-notify--test-tmpfile (file-notify--test-make-temp-name) | |
200 | file-notify--test-tmpfile1 (file-notify--test-make-temp-name) | |
201 | desc | |
202 | (file-notify-add-watch | |
203 | file-notify--test-tmpfile | |
204 | '(change) 'file-notify--test-event-handler)) | |
205 | ||
206 | ;; Check creation and removal. | |
927fbd6b MA |
207 | (write-region |
208 | "any text" nil file-notify--test-tmpfile nil 'no-message) | |
4ddbf128 | 209 | (delete-file file-notify--test-tmpfile) |
40d2f2e4 | 210 | (sleep-for 0.1) |
4ddbf128 MA |
211 | |
212 | ;; Check copy and rename. | |
927fbd6b MA |
213 | (write-region |
214 | "any text" nil file-notify--test-tmpfile nil 'no-message) | |
4ddbf128 MA |
215 | (copy-file file-notify--test-tmpfile file-notify--test-tmpfile1) |
216 | (delete-file file-notify--test-tmpfile) | |
217 | (delete-file file-notify--test-tmpfile1) | |
40d2f2e4 | 218 | (sleep-for 0.1) |
4ddbf128 | 219 | |
927fbd6b MA |
220 | (write-region |
221 | "any text" nil file-notify--test-tmpfile nil 'no-message) | |
4ddbf128 | 222 | (rename-file file-notify--test-tmpfile file-notify--test-tmpfile1) |
63389c25 | 223 | (delete-file file-notify--test-tmpfile1) |
40d2f2e4 | 224 | (sleep-for 0.1)) |
4ddbf128 MA |
225 | |
226 | ;; Wait for events, and exit. | |
63389c25 | 227 | (file-notify--wait-for-events 5 file-notify--test-results) |
4ddbf128 MA |
228 | (file-notify-rm-watch desc) |
229 | (ignore-errors (delete-file file-notify--test-tmpfile)) | |
230 | (ignore-errors (delete-file file-notify--test-tmpfile1)))) | |
59eb37e5 | 231 | |
5511e5c5 | 232 | (should file-notify--test-results) |
4ddbf128 MA |
233 | (dolist (result file-notify--test-results) |
234 | ;(message "%s" (ert-test-result-messages result)) | |
235 | (when (ert-test-failed-p result) | |
236 | (ert-fail (cadr (ert-test-result-with-condition-condition result)))))) | |
237 | ||
238 | (file-notify--deftest-remote file-notify-test02-events | |
239 | "Check file creation/removal notifications for remote files.") | |
46e4f821 | 240 | |
46e4f821 | 241 | (defvar auto-revert-remote-files) |
23293cb0 MA |
242 | (defvar auto-revert-stop-on-user-input) |
243 | (setq auto-revert-remote-files t | |
244 | auto-revert-stop-on-user-input nil) | |
46e4f821 | 245 | (require 'autorevert) |
46e4f821 | 246 | |
4ddbf128 MA |
247 | (ert-deftest file-notify-test03-autorevert () |
248 | "Check autorevert via file notification. | |
46e4f821 | 249 | This test is skipped in batch mode." |
4ddbf128 | 250 | (skip-unless (file-notify--test-local-enabled)) |
4ddbf128 MA |
251 | ;; `auto-revert-buffers' runs every 5". And we must wait, until the |
252 | ;; file has been reverted. | |
1baa1e49 MA |
253 | (let* ((remote (file-remote-p temporary-file-directory)) |
254 | (timeout (if remote 60 10)) | |
255 | buf) | |
4ddbf128 MA |
256 | (unwind-protect |
257 | (progn | |
258 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)) | |
259 | ||
927fbd6b MA |
260 | (write-region |
261 | "any text" nil file-notify--test-tmpfile nil 'no-message) | |
4ddbf128 MA |
262 | (setq buf (find-file-noselect file-notify--test-tmpfile)) |
263 | (with-current-buffer buf | |
264 | (should (string-equal (buffer-string) "any text")) | |
265 | (auto-revert-mode 1) | |
266 | ||
267 | ;; `auto-revert-buffers' runs every 5". | |
268 | (with-timeout (timeout (ignore)) | |
269 | (while (null auto-revert-notify-watch-descriptor) | |
40d2f2e4 | 270 | (sleep-for 1))) |
4ddbf128 MA |
271 | |
272 | ;; Check, that file notification has been used. | |
273 | (should auto-revert-mode) | |
274 | (should auto-revert-use-notify) | |
275 | (should auto-revert-notify-watch-descriptor) | |
276 | ||
277 | ;; Modify file. We wait for a second, in order to | |
278 | ;; have another timestamp. | |
40d2f2e4 | 279 | (sleep-for 1) |
4ddbf128 MA |
280 | (shell-command |
281 | (format "echo -n 'another text' >%s" | |
282 | (or (file-remote-p file-notify--test-tmpfile 'localname) | |
283 | file-notify--test-tmpfile))) | |
284 | ||
285 | ;; Check, that the buffer has been reverted. | |
286 | (with-current-buffer (get-buffer-create "*Messages*") | |
63389c25 MA |
287 | (file-notify--wait-for-events |
288 | timeout | |
289 | (string-match (format "Reverting buffer `%s'." (buffer-name buf)) | |
290 | (buffer-string)))) | |
1baa1e49 | 291 | (should (string-match "another text" (buffer-string))))) |
4ddbf128 MA |
292 | |
293 | ;; Exit. | |
294 | (ignore-errors (kill-buffer buf)) | |
295 | (ignore-errors (delete-file file-notify--test-tmpfile))))) | |
296 | ||
297 | (file-notify--deftest-remote file-notify-test03-autorevert | |
298 | "Check autorevert via file notification for remote files. | |
84b6d3df | 299 | This test is skipped in batch mode.") |
46e4f821 MA |
300 | |
301 | (defun file-notify-test-all (&optional interactive) | |
302 | "Run all tests for \\[file-notify]." | |
303 | (interactive "p") | |
4ddbf128 MA |
304 | (if interactive |
305 | (ert-run-tests-interactively "^file-notify-") | |
306 | (ert-run-tests-batch "^file-notify-"))) | |
46e4f821 MA |
307 | |
308 | (provide 'file-notify-tests) | |
309 | ;;; file-notify-tests.el ends here |