AtlatestRepositorycourier
1
(import (sigil test)2
(sigil string)3
(sigil math)4
(sigil json)5
(courier telegram)6
(courier relay))8
;; ============================================================9
;; Media type detection by extension10
;; ============================================================12
(test-group "path-media-type"13
(test "png is photo"14
(assert-equal 'photo (path-media-type "/tmp/screenshot.png")))16
(test "jpg is photo"17
(assert-equal 'photo (path-media-type "/tmp/photo.jpg")))19
(test "jpeg is photo"20
(assert-equal 'photo (path-media-type "image.jpeg")))22
(test "uppercase extension still detected"23
;; Extensions are downcased before comparison24
(assert-equal 'photo (path-media-type "/tmp/IMG_001.JPG")))26
(test "gif is photo"27
(assert-equal 'photo (path-media-type "/tmp/sticker.gif")))29
(test "webp is photo"30
(assert-equal 'photo (path-media-type "/tmp/sticker.webp")))32
(test "mp4 is video"33
(assert-equal 'video (path-media-type "/tmp/recording.mp4")))35
(test "mkv is video"36
(assert-equal 'video (path-media-type "/tmp/clip.mkv")))38
(test "mov is video"39
(assert-equal 'video (path-media-type "/tmp/clip.mov")))41
(test "webm is video"42
(assert-equal 'video (path-media-type "/tmp/clip.webm")))44
(test "pdf is document"45
(assert-equal 'document (path-media-type "/tmp/report.pdf")))47
(test "zip is document"48
(assert-equal 'document (path-media-type "/tmp/bundle.zip")))50
(test "no extension is document"51
;; Files without extensions are safest as documents — Telegram52
;; rejects sendPhoto/sendVideo when content type doesn't match.53
(assert-equal 'document (path-media-type "/tmp/Makefile")))55
(test "unknown extension is document"56
(assert-equal 'document (path-media-type "/tmp/data.xyz"))))58
;; ============================================================59
;; Media-upload envelope shape (relay wire protocol)60
;; ============================================================62
(test-group "make-media-upload-envelope"63
(test "minimal envelope has required fields"64
(let* ((json (make-media-upload-envelope "/tmp/x.png"))65
(env (json-decode json)))66
(assert-equal "media-upload" (dict-ref env type:))67
(assert-equal "worker" (dict-ref env sender:))68
(assert-equal "/tmp/x.png" (dict-ref env path:))69
(assert-false (dict-ref env to: #f))70
(assert-false (dict-ref env caption: #f))71
(assert-false (dict-ref env media-type: #f))))73
(test "all optional fields round-trip"74
(let* ((json (make-media-upload-envelope "/tmp/clip.mp4"75
to: "999" caption: "hi" media-type: "video"))76
(env (json-decode json)))77
(assert-equal "/tmp/clip.mp4" (dict-ref env path:))78
(assert-equal "999" (dict-ref env to:))79
(assert-equal "hi" (dict-ref env caption:))80
(assert-equal "video" (dict-ref env media-type:))))82
(test "envelope is a single line of JSON"83
;; Relay wire protocol is newline-delimited; the envelope84
;; itself must not contain a newline.85
(let ((json (make-media-upload-envelope "/tmp/a.gif" caption: "n")))86
(assert-false (string-contains? json "\n")))))88
;; ============================================================89
;; format-size human-readable byte counts90
;; ============================================================92
(test-group "format-size"93
(test "small files use bytes"94
(assert-equal "0 B" (format-size 0))95
(assert-equal "1023 B" (format-size 1023)))97
(test "kilobyte range"98
(assert-equal "1 KB" (format-size 1024))99
(assert-equal "500 KB" (format-size (* 500 1024))))101
(test "megabyte range with one decimal"102
(assert-equal "1.0 MB" (format-size (* 1024 1024)))103
;; 2.5 MB exactly = 2621440 bytes; integer truncation gives "2.5 MB"104
(assert-equal "2.5 MB" (format-size (quotient (* 5 1024 1024) 2)))))106
;; ============================================================107
;; Send-result strings: a caller must be able to tell delivery108
;; from non-delivery by reading the return value109
;; ============================================================110
;;111
;; The dry-run path used to return "Message sent." byte-for-byte, so every112
;; gagged send from 2026-07-06 to 2026-08-04 claimed a delivery it had not113
;; made -- and mimicked the silent-drop bug it was masking exactly, which114
;; made production observation of that bug impossible while the gag was on.115
;; These pin the property that failure cost us: the strings must be116
;; DISTINGUISHABLE. The end-to-end behaviour (what the MCP tool actually117
;; returns, and that a gagged send does not poison a later real one) is118
;; proved by repro/repro-single-poller.sh cases 5 and 6.120
(test-group "send-result strings"121
(test "the dry-run string does not contain a bare 'Message sent'"122
(assert-true (not (string-contains? *dry-run-not-sent-message*123
"Message sent"))))125
(test "the dry-run string does not begin with 'Message sent'"126
(assert-true (not (string-starts-with? *dry-run-not-sent-message*127
"Message sent"))))129
(test "the dry-run string says plainly that nothing was delivered"130
(assert-true (string-contains? *dry-run-not-sent-message* "NOT sent"))131
(assert-true (string-contains? *dry-run-not-sent-message*132
"COURIER_DISABLE_TELEGRAM_SEND")))134
(test "the duplicate-suppressed string is not the plain success string"135
(assert-true (not (string=? *duplicate-suppressed-message*136
"Message sent.")))137
(assert-true (string-contains? *duplicate-suppressed-message*138
"duplicate suppressed")))140
(test "the two non-delivery strings are distinct from each other"141
(assert-true (not (string=? *dry-run-not-sent-message*142
*duplicate-suppressed-message*)))))144
(run-tests)