aboutsummaryrefslogtreecommitdiff
path: root/tests/test-wttrin--get-cached-or-fetch.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-02-21 07:06:50 -0600
committerCraig Jennings <c@cjennings.net>2026-02-21 07:11:03 -0600
commitb74b98f177d92d50ddbede900ba41212e07c5f63 (patch)
tree459b1630dcc7d1c941f850565acdc16332831948 /tests/test-wttrin--get-cached-or-fetch.el
parentec8130cfe1a7390e9939b311c8db39907a3f7f44 (diff)
downloademacs-wttrin-b74b98f177d92d50ddbede900ba41212e07c5f63.tar.gz
emacs-wttrin-b74b98f177d92d50ddbede900ba41212e07c5f63.zip
feat: unified cache and staleness handling for mode-line and buffer
Replace TTL-based cache invalidation with proactive scheduled refresh. Both mode-line and buffer systems now follow: timer refreshes cache, display reads from cache, staleness indicated when data is old. Phase 1 - Mode-line cache formalization + staleness display: - Replace wttrin--mode-line-tooltip-data with wttrin--mode-line-cache as (timestamp . data) cons cell matching buffer cache pattern - Add wttrin--format-age helper for human-readable age strings - Rewrite wttrin--mode-line-update-display to take no arguments, read from cache, compute staleness (age > 2x refresh interval), dim emoji gray when stale, show staleness info in tooltip - Rewrite wttrin--mode-line-fetch-weather to write cache on success, show stale display on failure with cache, error placeholder without - Add wttrin--mode-line-update-placeholder-error for first-launch failure Phase 2 - Remove TTL, add proactive buffer refresh: - Rename wttrin-cache-ttl to wttrin-refresh-interval (default 3600s) with define-obsolete-variable-alias for backward compatibility - Change wttrin-mode-line-refresh-interval default from 900 to 3600 - Remove TTL check from wttrin--get-cached-or-fetch; serve cached data regardless of age, background timer keeps it fresh - Add buffer refresh timer (wttrin--buffer-cache-refresh) Phase 3 - Buffer staleness display: - Add wttrin--format-staleness-header for buffer age display - Insert staleness line in wttrin--display-weather before instructions Phase 4 - Cleanup: - Remove all references to wttrin--mode-line-tooltip-data - Update README.org cache settings and mode-line documentation - Update tests for new API (198 tests across 21 files, all passing)
Diffstat (limited to 'tests/test-wttrin--get-cached-or-fetch.el')
-rw-r--r--tests/test-wttrin--get-cached-or-fetch.el109
1 files changed, 19 insertions, 90 deletions
diff --git a/tests/test-wttrin--get-cached-or-fetch.el b/tests/test-wttrin--get-cached-or-fetch.el
index 77a2689..e3383c6 100644
--- a/tests/test-wttrin--get-cached-or-fetch.el
+++ b/tests/test-wttrin--get-cached-or-fetch.el
@@ -5,7 +5,9 @@
;;; Commentary:
;; Unit tests for wttrin--get-cached-or-fetch function.
-;; Tests the core cache workflow: cache hits, misses, expiration, and error fallback.
+;; Tests the core cache workflow: cache hits, misses, and error fallback.
+;; TTL-based expiration has been removed — cached data is served regardless
+;; of age, with proactive refresh keeping data fresh in the background.
;;; Code:
@@ -36,7 +38,7 @@
;;; Normal Cases
(ert-deftest test-wttrin--get-cached-or-fetch-normal-cache-hit-returns-cached-data ()
- "Test that fresh cached data is returned without fetching."
+ "Test that cached data is returned without fetching."
(test-wttrin--get-cached-or-fetch-setup)
(unwind-protect
(let* ((location "Paris")
@@ -44,11 +46,11 @@
(now 1000.0)
(callback-result nil)
(fetch-called nil))
- ;; Pre-populate cache with fresh data
+ ;; Pre-populate cache with data
(puthash cache-key (cons now test-wttrin--get-cached-or-fetch-sample-weather)
wttrin--cache)
- ;; Mock time to be 100 seconds later (well within TTL of 900)
+ ;; Mock time to be 100 seconds later
(cl-letf (((symbol-function 'float-time)
(lambda () (+ now 100.0)))
((symbol-function 'wttrin-fetch-raw-string)
@@ -99,14 +101,15 @@
(should (equal (cdr cached) test-wttrin--get-cached-or-fetch-new-weather)))))
(test-wttrin--get-cached-or-fetch-teardown)))
-(ert-deftest test-wttrin--get-cached-or-fetch-normal-expired-cache-fetches-new-data ()
- "Test that expired cache triggers fetch and updates cache."
+(ert-deftest test-wttrin--get-cached-or-fetch-normal-old-data-still-served ()
+ "Test that old cached data is served without fetching (no TTL expiration).
+Proactive refresh keeps data fresh; on-demand reads always use cache."
(test-wttrin--get-cached-or-fetch-setup)
(unwind-protect
(let* ((location "Tokyo")
(cache-key (wttrin--make-cache-key location))
(old-time 1000.0)
- (new-time (+ old-time 1000.0)) ; 1000 seconds later (> 900 TTL)
+ (new-time (+ old-time 10000.0)) ; Very old data
(callback-result nil)
(fetch-called nil))
@@ -117,81 +120,6 @@
(cl-letf (((symbol-function 'float-time)
(lambda () new-time))
((symbol-function 'wttrin-fetch-raw-string)
- (lambda (_location callback)
- (setq fetch-called t)
- (funcall callback test-wttrin--get-cached-or-fetch-new-weather)))
- ((symbol-function 'wttrin--cleanup-cache-if-needed)
- (lambda () nil)))
-
- (wttrin--get-cached-or-fetch
- location
- (lambda (data) (setq callback-result data)))
-
- ;; Should call fetch due to expiration
- (should fetch-called)
- ;; Should return new data
- (should (equal callback-result test-wttrin--get-cached-or-fetch-new-weather))
- ;; Should update cache timestamp
- (let ((cached (gethash cache-key wttrin--cache)))
- (should (equal (car cached) new-time))
- (should (equal (cdr cached) test-wttrin--get-cached-or-fetch-new-weather)))))
- (test-wttrin--get-cached-or-fetch-teardown)))
-
-;;; Boundary Cases
-
-(ert-deftest test-wttrin--get-cached-or-fetch-boundary-exactly-at-ttl-fetches ()
- "Test that cache exactly at TTL boundary triggers fetch."
- (test-wttrin--get-cached-or-fetch-setup)
- (unwind-protect
- (let* ((location "Berlin")
- (cache-key (wttrin--make-cache-key location))
- (old-time 1000.0)
- ;; Exactly at TTL boundary (900 seconds = wttrin-cache-ttl)
- (new-time (+ old-time wttrin-cache-ttl))
- (callback-result nil)
- (fetch-called nil))
-
- ;; Pre-populate cache
- (puthash cache-key (cons old-time test-wttrin--get-cached-or-fetch-sample-weather)
- wttrin--cache)
-
- (cl-letf (((symbol-function 'float-time)
- (lambda () new-time))
- ((symbol-function 'wttrin-fetch-raw-string)
- (lambda (_location callback)
- (setq fetch-called t)
- (funcall callback test-wttrin--get-cached-or-fetch-new-weather)))
- ((symbol-function 'wttrin--cleanup-cache-if-needed)
- (lambda () nil)))
-
- (wttrin--get-cached-or-fetch
- location
- (lambda (data) (setq callback-result data)))
-
- ;; At exactly TTL, should fetch (not <)
- (should fetch-called)
- (should (equal callback-result test-wttrin--get-cached-or-fetch-new-weather))))
- (test-wttrin--get-cached-or-fetch-teardown)))
-
-(ert-deftest test-wttrin--get-cached-or-fetch-boundary-one-second-before-ttl-uses-cache ()
- "Test that cache one second before TTL uses cached data."
- (test-wttrin--get-cached-or-fetch-setup)
- (unwind-protect
- (let* ((location "Madrid")
- (cache-key (wttrin--make-cache-key location))
- (old-time 1000.0)
- ;; One second before TTL expiration
- (new-time (+ old-time (- wttrin-cache-ttl 1)))
- (callback-result nil)
- (fetch-called nil))
-
- ;; Pre-populate cache
- (puthash cache-key (cons old-time test-wttrin--get-cached-or-fetch-sample-weather)
- wttrin--cache)
-
- (cl-letf (((symbol-function 'float-time)
- (lambda () new-time))
- ((symbol-function 'wttrin-fetch-raw-string)
(lambda (_location _callback)
(setq fetch-called t))))
@@ -199,11 +127,13 @@
location
(lambda (data) (setq callback-result data)))
- ;; Should use cache (still fresh)
+ ;; Should serve old data without fetching
(should-not fetch-called)
(should (equal callback-result test-wttrin--get-cached-or-fetch-sample-weather))))
(test-wttrin--get-cached-or-fetch-teardown)))
+;;; Boundary Cases
+
(ert-deftest test-wttrin--get-cached-or-fetch-boundary-force-refresh-bypasses-fresh-cache ()
"Test that force refresh flag bypasses fresh cache."
(test-wttrin--get-cached-or-fetch-setup)
@@ -220,7 +150,7 @@
wttrin--cache)
(cl-letf (((symbol-function 'float-time)
- (lambda () (+ now 100.0))) ; Well within TTL
+ (lambda () (+ now 100.0)))
((symbol-function 'wttrin-fetch-raw-string)
(lambda (_location callback)
(setq fetch-called t)
@@ -314,17 +244,16 @@
(unwind-protect
(let* ((location "Vienna")
(cache-key (wttrin--make-cache-key location))
- (old-time 1000.0)
- (new-time (+ old-time 2000.0)) ; Well expired
(callback-result nil)
- (message-shown nil))
+ (message-shown nil)
+ (wttrin--force-refresh t)) ; Force refresh to trigger fetch
- ;; Pre-populate cache with expired data
- (puthash cache-key (cons old-time test-wttrin--get-cached-or-fetch-sample-weather)
+ ;; Pre-populate cache with data
+ (puthash cache-key (cons 1000.0 test-wttrin--get-cached-or-fetch-sample-weather)
wttrin--cache)
(cl-letf (((symbol-function 'float-time)
- (lambda () new-time))
+ (lambda () 3000.0))
((symbol-function 'wttrin-fetch-raw-string)
(lambda (_location callback)
;; Simulate network failure