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