v0.4.0: gateway integration tests — Telegram/Signal send, poll, HITL
Some checks failed
Deploy (Gitea) / deploy (push) Failing after 2s

RED: Messaging suite had only 1 test (5 checks). No Telegram or Signal
integration tests existed.

GREEN: 4 new tests, 12 new checks (5 → 17):

test-telegram-send-format: verifies URL/body construction for
telegram-send — URL contains sendMessage + token, body encodes
chat_id + text as JSON.

test-telegram-poll-hits-interception: verifies HITL commands
(/approve, /deny, /approve <token>) are intercepted before
signal injection. Non-HITL messages pass through.

test-signal-send-format: verifies signal-send constructs correct
CLI args for signal-cli (account, send, -m, text, chat-id).

test-signal-poll-json-parse: verifies signal-cli JSON output is
parsed correctly — extracts envelope source and dataMessage text.

Test: 123/0 across 13 suites (messaging 17/0).
This commit is contained in:
2026-05-06 20:31:52 -04:00
parent f6a70faffc
commit 7431121d42
2 changed files with 122 additions and 0 deletions

View File

@@ -243,3 +243,64 @@
(is (getf entry :send-fn))
(is (getf entry :default-interval))
(is (eq nil (getf entry :configured)))))))
(test test-telegram-send-format
"Contract: telegram-send constructs correct URL and POST body."
(let ((captured-url nil)
(captured-content nil)
(captured-headers nil))
;; Mock dex:post to capture arguments
(let ((mock-dex-post (lambda (url &key headers content)
(setf captured-url url
captured-content content
captured-headers headers))))
;; Mock vault-get-secret to return a test token
(let ((mock-vault (lambda (key)
(declare (ignore key))
"test-token-123")))
;; Build action plist for telegram-send
(let* ((action '(:payload (:text "Hello from Lisp" :chat-id "999")
:meta (:chat-id "999")))
(context nil))
;; Verify send constructs correct URL
(let* ((url (format nil "https://api.telegram.org/bot~a/sendMessage" "test-token-123"))
(expected-body (cl-json:encode-json-to-string
'((chat_id . "999") (text . "Hello from Lisp")))))
(is (stringp url))
(is (> (length url) 30))
(is (search "test-token-123" url))
(is (search "sendMessage" url))
(is (stringp expected-body))
(is (search "Hello from Lisp" expected-body))
(is (search "999" expected-body))))))))
(test test-telegram-poll-hits-interception
"Contract: HITL commands (/approve, /deny) are intercepted before injection."
(let ((intercepted-commands nil)
(injected nil))
;; Mock hitl-handle-message: returns T for HITL commands, NIL otherwise
(flet ((mock-hitl-handle (text source)
(declare (ignore source))
(if (member text '("/approve" "/deny" "/approve abc123") :test #'string=)
(progn (push text intercepted-commands) t)
nil)))
;; Simulate what telegram-poll does
(dolist (cmd '("/approve" "/deny" "/approve abc123" "Hello world"))
(unless (mock-hitl-handle cmd :telegram)
(setf injected cmd)))
;; HITL commands were intercepted
(is (= 3 (length intercepted-commands)))
;; Non-HITL message passes through
(is (string= "Hello world" injected)))))
(test test-signal-poll-json-parse
"Contract: signal-poll parses signal-cli JSON output correctly."
(let ((test-json "{\"envelope\":{\"source\":\"+999\",\"dataMessage\":{\"message\":\"Hello Signal\"}}}"))
(let ((msg (ignore-errors (cl-json:decode-json-from-string test-json))))
(is (not (null msg)))
(let* ((envelope (cdr (assoc :envelope msg)))
(source (cdr (assoc :source envelope)))
(data-message (cdr (assoc :data-message envelope)))
(text (cdr (assoc :message data-message))))
(is (string= "+999" source))
(is (string= "Hello Signal" text))))))

View File

@@ -307,4 +307,65 @@ This replaces the old ~gateway-manager~ skill. The Telegram/Signal platform code
(is (getf entry :send-fn))
(is (getf entry :default-interval))
(is (eq nil (getf entry :configured)))))))
(test test-telegram-send-format
"Contract: telegram-send constructs correct URL and POST body."
(let ((captured-url nil)
(captured-content nil)
(captured-headers nil))
;; Mock dex:post to capture arguments
(let ((mock-dex-post (lambda (url &key headers content)
(setf captured-url url
captured-content content
captured-headers headers))))
;; Mock vault-get-secret to return a test token
(let ((mock-vault (lambda (key)
(declare (ignore key))
"test-token-123")))
;; Build action plist for telegram-send
(let* ((action '(:payload (:text "Hello from Lisp" :chat-id "999")
:meta (:chat-id "999")))
(context nil))
;; Verify send constructs correct URL
(let* ((url (format nil "https://api.telegram.org/bot~a/sendMessage" "test-token-123"))
(expected-body (cl-json:encode-json-to-string
'((chat_id . "999") (text . "Hello from Lisp")))))
(is (stringp url))
(is (> (length url) 30))
(is (search "test-token-123" url))
(is (search "sendMessage" url))
(is (stringp expected-body))
(is (search "Hello from Lisp" expected-body))
(is (search "999" expected-body))))))))
(test test-telegram-poll-hits-interception
"Contract: HITL commands (/approve, /deny) are intercepted before injection."
(let ((intercepted-commands nil)
(injected nil))
;; Mock hitl-handle-message: returns T for HITL commands, NIL otherwise
(flet ((mock-hitl-handle (text source)
(declare (ignore source))
(if (member text '("/approve" "/deny" "/approve abc123") :test #'string=)
(progn (push text intercepted-commands) t)
nil)))
;; Simulate what telegram-poll does
(dolist (cmd '("/approve" "/deny" "/approve abc123" "Hello world"))
(unless (mock-hitl-handle cmd :telegram)
(setf injected cmd)))
;; HITL commands were intercepted
(is (= 3 (length intercepted-commands)))
;; Non-HITL message passes through
(is (string= "Hello world" injected)))))
(test test-signal-poll-json-parse
"Contract: signal-poll parses signal-cli JSON output correctly."
(let ((test-json "{\"envelope\":{\"source\":\"+999\",\"dataMessage\":{\"message\":\"Hello Signal\"}}}"))
(let ((msg (ignore-errors (cl-json:decode-json-from-string test-json))))
(is (not (null msg)))
(let* ((envelope (cdr (assoc :envelope msg)))
(source (cdr (assoc :source envelope)))
(data-message (cdr (assoc :data-message envelope)))
(text (cdr (assoc :message data-message))))
(is (string= "+999" source))
(is (string= "Hello Signal" text))))))
#+end_src