Commit | Line | Data |
---|---|---|
46e4f821 MA |
1 | ;;; file-notify-tests.el --- Tests of file notifications |
2 | ||
3 | ;; Copyright (C) 2013 Free Software Foundation, Inc. | |
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 | |
70 | (not (file-remote-p temporary-file-directory)))) | |
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)) | |
105 | ;; The local test could have passed, skipped, or quit. All of | |
106 | ;; these results should not prevent us to run the remote test. | |
107 | ;; That's why we skip only for failed local tests. | |
108 | (skip-unless | |
109 | (not (ert-test-failed-p (ert-test-most-recent-result ert-test)))) | |
1baa1e49 MA |
110 | (tramp-cleanup-connection |
111 | (tramp-dissect-file-name temporary-file-directory) nil 'keep-password) | |
4ddbf128 | 112 | (funcall (ert-test-body ert-test))))) |
84b6d3df MA |
113 | |
114 | (ert-deftest file-notify-test00-availability () | |
115 | "Test availability of `file-notify'." | |
4ddbf128 | 116 | (skip-unless (file-notify--test-local-enabled)) |
e81dd54d MA |
117 | (let (desc) |
118 | ;; Check, that different valid parameters are accepted. | |
119 | (should (setq desc (file-notify-add-watch | |
120 | temporary-file-directory '(change) 'ignore))) | |
121 | (file-notify-rm-watch desc))) | |
122 | ||
123 | (file-notify--deftest-remote file-notify-test00-availability | |
124 | "Test availability of `file-notify' for remote files.") | |
46e4f821 | 125 | |
4ddbf128 MA |
126 | (ert-deftest file-notify-test01-add-watch () |
127 | "Check `file-notify-add-watch'." | |
128 | (skip-unless (file-notify--test-local-enabled)) | |
129 | (let (desc) | |
130 | ;; Check, that different valid parameters are accepted. | |
131 | (should (setq desc (file-notify-add-watch | |
132 | temporary-file-directory '(change) 'ignore))) | |
133 | (file-notify-rm-watch desc) | |
134 | (should (setq desc (file-notify-add-watch | |
135 | temporary-file-directory | |
136 | '(attribute-change) 'ignore))) | |
137 | (file-notify-rm-watch desc) | |
138 | (should (setq desc (file-notify-add-watch | |
139 | temporary-file-directory | |
140 | '(change attribute-change) 'ignore))) | |
141 | (file-notify-rm-watch desc) | |
46e4f821 | 142 | |
4ddbf128 MA |
143 | ;; Check error handling. |
144 | (should-error (file-notify-add-watch 1 2 3 4) | |
145 | :type 'wrong-number-of-arguments) | |
146 | (should | |
147 | (equal (should-error (file-notify-add-watch 1 2 3)) | |
148 | '(wrong-type-argument 1))) | |
149 | (should | |
150 | (equal (should-error (file-notify-add-watch | |
151 | temporary-file-directory 2 3)) | |
152 | '(wrong-type-argument 2))) | |
153 | (should | |
154 | (equal (should-error (file-notify-add-watch | |
155 | temporary-file-directory '(change) 3)) | |
156 | '(wrong-type-argument 3))))) | |
59eb37e5 | 157 | |
4ddbf128 MA |
158 | (file-notify--deftest-remote file-notify-test01-add-watch |
159 | "Check `file-notify-add-watch' for remote files.") | |
46e4f821 | 160 | |
84b6d3df MA |
161 | (defun file-notify--test-event-test () |
162 | "Ert test function to be called by `file-notify--test-event-handler'. | |
163 | We cannot pass arguments, so we assume that `file-notify--test-event' | |
46e4f821 | 164 | is bound somewhere." |
84b6d3df | 165 | ;(message "Event %S" file-notify--test-event) |
46e4f821 MA |
166 | ;; Check the file name. |
167 | (should | |
84b6d3df MA |
168 | (string-equal (file-notify--event-file-name file-notify--test-event) |
169 | file-notify--test-tmpfile)) | |
46e4f821 | 170 | ;; Check the second file name if exists. |
84b6d3df | 171 | (when (eq (nth 1 file-notify--test-event) 'renamed) |
46e4f821 MA |
172 | (should |
173 | (string-equal | |
84b6d3df MA |
174 | (file-notify--event-file1-name file-notify--test-event) |
175 | file-notify--test-tmpfile1)))) | |
176 | ||
177 | (defun file-notify--test-event-handler (file-notify--test-event) | |
178 | "Run a test over FILE-NOTIFY--TEST-EVENT. | |
179 | Save the result in `file-notify--test-results', for later analysis." | |
180 | (let ((result | |
181 | (ert-run-test (make-ert-test :body 'file-notify--test-event-test)))) | |
182 | (setq file-notify--test-results | |
183 | (append file-notify--test-results `(,result))))) | |
184 | ||
185 | (defun file-notify--test-make-temp-name () | |
46e4f821 MA |
186 | "Create a temporary file name for test." |
187 | (expand-file-name | |
188 | (make-temp-name "file-notify-test") temporary-file-directory)) | |
189 | ||
4ddbf128 MA |
190 | (ert-deftest file-notify-test02-events () |
191 | "Check file creation/removal notifications." | |
192 | (skip-unless (file-notify--test-local-enabled)) | |
193 | (let (desc) | |
194 | (unwind-protect | |
195 | (progn | |
196 | (setq file-notify--test-results nil | |
197 | file-notify--test-tmpfile (file-notify--test-make-temp-name) | |
198 | file-notify--test-tmpfile1 (file-notify--test-make-temp-name) | |
199 | desc | |
200 | (file-notify-add-watch | |
201 | file-notify--test-tmpfile | |
202 | '(change) 'file-notify--test-event-handler)) | |
203 | ||
204 | ;; Check creation and removal. | |
927fbd6b MA |
205 | (write-region |
206 | "any text" nil file-notify--test-tmpfile nil 'no-message) | |
4ddbf128 MA |
207 | (delete-file file-notify--test-tmpfile) |
208 | ||
209 | ;; Check copy and rename. | |
927fbd6b MA |
210 | (write-region |
211 | "any text" nil file-notify--test-tmpfile nil 'no-message) | |
4ddbf128 MA |
212 | (copy-file file-notify--test-tmpfile file-notify--test-tmpfile1) |
213 | (delete-file file-notify--test-tmpfile) | |
214 | (delete-file file-notify--test-tmpfile1) | |
215 | ||
927fbd6b MA |
216 | (write-region |
217 | "any text" nil file-notify--test-tmpfile nil 'no-message) | |
4ddbf128 MA |
218 | (rename-file file-notify--test-tmpfile file-notify--test-tmpfile1) |
219 | (delete-file file-notify--test-tmpfile1)) | |
220 | ||
221 | ;; Wait for events, and exit. | |
222 | (sit-for 5 'nodisplay) | |
223 | (file-notify-rm-watch desc) | |
224 | (ignore-errors (delete-file file-notify--test-tmpfile)) | |
225 | (ignore-errors (delete-file file-notify--test-tmpfile1)))) | |
59eb37e5 | 226 | |
4ddbf128 MA |
227 | (dolist (result file-notify--test-results) |
228 | ;(message "%s" (ert-test-result-messages result)) | |
229 | (when (ert-test-failed-p result) | |
230 | (ert-fail (cadr (ert-test-result-with-condition-condition result)))))) | |
231 | ||
232 | (file-notify--deftest-remote file-notify-test02-events | |
233 | "Check file creation/removal notifications for remote files.") | |
46e4f821 | 234 | |
46e4f821 | 235 | (defvar auto-revert-remote-files) |
23293cb0 MA |
236 | (defvar auto-revert-stop-on-user-input) |
237 | (setq auto-revert-remote-files t | |
238 | auto-revert-stop-on-user-input nil) | |
46e4f821 | 239 | (require 'autorevert) |
46e4f821 | 240 | |
4ddbf128 MA |
241 | (ert-deftest file-notify-test03-autorevert () |
242 | "Check autorevert via file notification. | |
46e4f821 | 243 | This test is skipped in batch mode." |
4ddbf128 | 244 | (skip-unless (file-notify--test-local-enabled)) |
4ddbf128 MA |
245 | ;; `auto-revert-buffers' runs every 5". And we must wait, until the |
246 | ;; file has been reverted. | |
1baa1e49 MA |
247 | (let* ((remote (file-remote-p temporary-file-directory)) |
248 | (timeout (if remote 60 10)) | |
249 | buf) | |
4ddbf128 MA |
250 | (unwind-protect |
251 | (progn | |
252 | (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)) | |
253 | ||
927fbd6b MA |
254 | (write-region |
255 | "any text" nil file-notify--test-tmpfile nil 'no-message) | |
4ddbf128 MA |
256 | (setq buf (find-file-noselect file-notify--test-tmpfile)) |
257 | (with-current-buffer buf | |
258 | (should (string-equal (buffer-string) "any text")) | |
259 | (auto-revert-mode 1) | |
260 | ||
261 | ;; `auto-revert-buffers' runs every 5". | |
262 | (with-timeout (timeout (ignore)) | |
263 | (while (null auto-revert-notify-watch-descriptor) | |
1baa1e49 | 264 | (sit-for 1 'nodisplay))) |
4ddbf128 MA |
265 | |
266 | ;; Check, that file notification has been used. | |
267 | (should auto-revert-mode) | |
268 | (should auto-revert-use-notify) | |
269 | (should auto-revert-notify-watch-descriptor) | |
270 | ||
271 | ;; Modify file. We wait for a second, in order to | |
272 | ;; have another timestamp. | |
273 | (sit-for 1) | |
274 | (shell-command | |
275 | (format "echo -n 'another text' >%s" | |
276 | (or (file-remote-p file-notify--test-tmpfile 'localname) | |
277 | file-notify--test-tmpfile))) | |
278 | ||
279 | ;; Check, that the buffer has been reverted. | |
280 | (with-current-buffer (get-buffer-create "*Messages*") | |
84b6d3df | 281 | (with-timeout (timeout (ignore)) |
4ddbf128 MA |
282 | (while |
283 | (null (string-match | |
284 | (format "Reverting buffer `%s'." (buffer-name buf)) | |
285 | (buffer-string))) | |
1baa1e49 MA |
286 | ;; We must trigger the process filter to run. |
287 | (when remote (accept-process-output nil 1)) | |
288 | (sit-for 1 'nodisplay)))) | |
289 | (should (string-match "another text" (buffer-string))))) | |
4ddbf128 MA |
290 | |
291 | ;; Exit. | |
292 | (ignore-errors (kill-buffer buf)) | |
293 | (ignore-errors (delete-file file-notify--test-tmpfile))))) | |
294 | ||
295 | (file-notify--deftest-remote file-notify-test03-autorevert | |
296 | "Check autorevert via file notification for remote files. | |
84b6d3df | 297 | This test is skipped in batch mode.") |
46e4f821 MA |
298 | |
299 | (defun file-notify-test-all (&optional interactive) | |
300 | "Run all tests for \\[file-notify]." | |
301 | (interactive "p") | |
4ddbf128 MA |
302 | (if interactive |
303 | (ert-run-tests-interactively "^file-notify-") | |
304 | (ert-run-tests-batch "^file-notify-"))) | |
46e4f821 MA |
305 | |
306 | (provide 'file-notify-tests) | |
307 | ;;; file-notify-tests.el ends here |