blob: 1281120021db8daba57cfa19ab4ec776d1aa6cdb (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
;;; test-calendar-sync--batch-report.el --- Batch report output tests -*- lexical-binding: t; -*-
;;; Commentary:
;; `calendar-sync-batch-run-and-report' is what the systemd timer runs, so its
;; printed rows are the only record that survives the process. Batch Emacs
;; discards *Messages* at exit, which is where the interactive failure path
;; logs its reason -- so a failed row has to carry its recorded `:last-error'
;; in the printed output or the journal shows "error" with no way to tell a
;; cold gpg-agent from a revoked feed token or a dead network.
;;; Code:
(require 'ert)
(require 'cl-lib) ;; cl-letf; calendar-sync pulls it in transitively, don't rely on that
(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
(require 'calendar-sync)
(defun test-calendar-sync-batch-report--capture (states results)
"Return the report's printed output for STATES and RESULTS.
STATES is an alist of NAME . PLIST seeded into the state table; RESULTS is
what `calendar-sync-batch-run' is stubbed to return, so the report is
exercised without driving a real sync."
(let ((calendar-sync--calendar-states (make-hash-table :test 'equal)))
(dolist (entry states)
(puthash (car entry) (cdr entry) calendar-sync--calendar-states))
(cl-letf (((symbol-function 'calendar-sync-batch-run)
(lambda (&rest _) results)))
(with-output-to-string
(calendar-sync-batch-run-and-report)))))
;;; Normal
(ert-deftest test-calendar-sync-batch-report-failed-row-carries-its-reason ()
"Normal: a failed calendar prints the recorded `:last-error' reason.
Without it the journal records only \"error\", and the operator cannot tell a
cold gpg-agent from a revoked token without re-running the sync by hand."
(let ((out (test-calendar-sync-batch-report--capture
'(("google" . (:status error :last-error "Decryption failed"))
("proton" . (:status ok)))
'(("google" . error) ("proton" . ok)))))
(should (string-match-p "google: error" out))
(should (string-match-p "Decryption failed" out))))
(ert-deftest test-calendar-sync-batch-report-ok-row-stays-bare ()
"Normal: a calendar that synced prints its status and nothing more.
A stale `:last-error' from an earlier failure must not be appended to a row
that succeeded this run."
(let ((out (test-calendar-sync-batch-report--capture
'(("google" . (:status ok :last-error "Decryption failed")))
'(("google" . ok)))))
(should (string-match-p "google: ok" out))
(should-not (string-match-p "Decryption failed" out))))
;;; Boundary
(ert-deftest test-calendar-sync-batch-report-failure-without-reason-still-prints ()
"Boundary: a failed row with no recorded reason prints its status alone.
`never' and `syncing' never record a `:last-error', so the reason lookup has
to tolerate nil rather than printing \"nil\" or signalling."
(let ((out (test-calendar-sync-batch-report--capture
'(("google" . (:status syncing)))
'(("google" . syncing) ("absent" . never)))))
(should (string-match-p "google: syncing" out))
(should (string-match-p "absent: never" out))
(should-not (string-match-p "nil" out))))
;;; Error
(defun test-calendar-sync-batch-report--exit-code (results)
"Return the report's exit code for RESULTS, discarding its printed output."
(let ((calendar-sync--calendar-states (make-hash-table :test 'equal)))
(cl-letf (((symbol-function 'calendar-sync-batch-run)
(lambda (&rest _) results)))
(with-temp-buffer
(let ((standard-output (current-buffer)))
(calendar-sync-batch-run-and-report))))))
(ert-deftest test-calendar-sync-batch-report-exit-code-tracks-failures ()
"Error: the return value becomes the process exit code, so it stays 1 on any
non-ok row and 0 only when every calendar synced. Appending the reason to the
printed line must not disturb it."
(should (equal 1 (test-calendar-sync-batch-report--exit-code '(("google" . error)))))
(should (equal 1 (test-calendar-sync-batch-report--exit-code
'(("google" . ok) ("proton" . never)))))
(should (equal 0 (test-calendar-sync-batch-report--exit-code '(("google" . ok))))))
(provide 'test-calendar-sync--batch-report)
;;; test-calendar-sync--batch-report.el ends here
|