blob: 04605175a350b0ee679b4c1416158e6affedc0de (
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
|
#!/bin/sh
set -eu
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
RMAIL_BIN=${RMAIL_BIN:-"$ROOT/out/rmail"}
MOCK_SENDMAIL_BIN=${MOCK_SENDMAIL_BIN:-"$ROOT/out/mock_sendmail"}
TMPDIR=${TMPDIR:-/tmp}
WORKDIR=$(mktemp -d "$TMPDIR/rmail-test.XXXXXX")
STDOUT_FILE="$WORKDIR/stdout"
STDERR_FILE="$WORKDIR/stderr"
SENDMAIL_LOG="$WORKDIR/sendmail-argv"
SENDMAIL_INPUT="$WORKDIR/sendmail-input"
LAST_STATUS=0
LAST_STDOUT=
LAST_STDERR=
trap 'rm -rf "$WORKDIR"' EXIT INT TERM
export LC_ALL=C
EX_USAGE=64
EX_DATAERR=65
EX_UNAVAILABLE=69
fail() {
printf '%s\n' "FAIL: $1" >&2
exit 1
}
assert_eq() {
name=$1
expected=$2
actual=$3
if [ "$expected" != "$actual" ]; then
printf '%s\n' "FAIL: $name" >&2
printf '%s\n' "--- expected ---" >&2
printf '%s' "$expected" >&2
printf '\n%s\n' "--- actual ---" >&2
printf '%s' "$actual" >&2
printf '\n' >&2
exit 1
fi
}
assert_contains() {
name=$1
text=$2
pattern=$3
case $text in
*"$pattern"*) ;;
*) fail "$name" ;;
esac
}
assert_empty() {
name=$1
text=$2
if [ -n "$text" ]; then
printf '%s\n' "FAIL: $name" >&2
printf '%s\n' "--- expected empty ---" >&2
printf '%s\n' "--- actual ---" >&2
printf '%s' "$text" >&2
printf '\n' >&2
exit 1
fi
}
assert_status() {
name=$1
expected=$2
actual=$3
if [ "$expected" -ne "$actual" ]; then
printf '%s\n' "FAIL: $name" >&2
printf '%s\n' "expected status: $expected" >&2
printf '%s\n' "actual status: $actual" >&2
exit 1
fi
}
run_capture() {
rm -f "$STDOUT_FILE" "$STDERR_FILE"
if "$@" >"$STDOUT_FILE" 2>"$STDERR_FILE"; then
LAST_STATUS=0
else
LAST_STATUS=$?
fi
LAST_STDOUT=$(cat "$STDOUT_FILE")
LAST_STDERR=$(cat "$STDERR_FILE")
}
run_with_input() {
input=$1
shift
rm -f "$STDOUT_FILE" "$STDERR_FILE"
if printf '%b' "$input" | "$@" >"$STDOUT_FILE" 2>"$STDERR_FILE"; then
LAST_STATUS=0
else
LAST_STATUS=$?
fi
LAST_STDOUT=$(cat "$STDOUT_FILE")
LAST_STDERR=$(cat "$STDERR_FILE")
}
run_with_regular_file() {
input_file=$1
shift
rm -f "$STDOUT_FILE" "$STDERR_FILE"
if "$@" <"$input_file" >"$STDOUT_FILE" 2>"$STDERR_FILE"; then
LAST_STATUS=0
else
LAST_STATUS=$?
fi
LAST_STDOUT=$(cat "$STDOUT_FILE")
LAST_STDERR=$(cat "$STDERR_FILE")
}
read_file() {
cat "$1"
}
[ -x "$RMAIL_BIN" ] || fail "missing binary: $RMAIL_BIN"
[ -x "$MOCK_SENDMAIL_BIN" ] || fail "missing mock sendmail: $MOCK_SENDMAIL_BIN"
export RMAIL_SENDMAIL="$MOCK_SENDMAIL_BIN"
export RMAIL_SENDMAIL_LOG="$SENDMAIL_LOG"
export RMAIL_SENDMAIL_INPUT="$SENDMAIL_INPUT"
unset RMAIL_SENDMAIL_EXIT
run_capture "$RMAIL_BIN"
assert_status "usage status" "$EX_USAGE" "$LAST_STATUS"
assert_empty "usage stdout" "$LAST_STDOUT"
assert_eq "usage stderr" "usage: rmail [-D domain] [-T] user ..." "$LAST_STDERR"
run_capture "$RMAIL_BIN" -D ''
assert_status "empty domain status" "$EX_USAGE" "$LAST_STATUS"
assert_empty "empty domain stdout" "$LAST_STDOUT"
assert_eq "empty domain stderr" "rmail: -D requires a non-empty domain" "$LAST_STDERR"
run_capture "$RMAIL_BIN" -- -bad@example.test
assert_status "dash recipient status" "$EX_USAGE" "$LAST_STATUS"
assert_empty "dash recipient stdout" "$LAST_STDOUT"
assert_eq "dash recipient stderr" "rmail: dash precedes argument: -bad@example.test" "$LAST_STDERR"
run_with_input '' "$RMAIL_BIN" user@example.test
assert_status "no data status" "$EX_DATAERR" "$LAST_STATUS"
assert_empty "no data stdout" "$LAST_STDOUT"
assert_eq "no data stderr" "rmail: no data" "$LAST_STDERR"
run_with_input 'Subject: hi\n\nbody\n' "$RMAIL_BIN" user@example.test
assert_status "missing from status" "$EX_DATAERR" "$LAST_STATUS"
assert_empty "missing from stdout" "$LAST_STDOUT"
assert_eq "missing from stderr" "rmail: missing or empty From line: Subject: hi" "$LAST_STDERR"
run_with_input 'From !bad Tue Jan 1 00:00:00 2025\n\nbody\n' "$RMAIL_BIN" user@example.test
assert_status "bang starts status" "$EX_DATAERR" "$LAST_STATUS"
assert_empty "bang starts stdout" "$LAST_STDOUT"
assert_eq "bang starts stderr" "rmail: bang starts address: !bad" "$LAST_STDERR"
run_with_input 'From user Tue Jan 1 00:00:00 2025' "$RMAIL_BIN" user@example.test
assert_status "unterminated header status" "$EX_DATAERR" "$LAST_STATUS"
assert_empty "unterminated header stdout" "$LAST_STDOUT"
assert_eq "unterminated header stderr" "rmail: unterminated input line" "$LAST_STDERR"
PIPE_INPUT='From host1!host2!alice Tue Jan 1 00:00:00 2025
>From bob Tue Jan 1 00:01:00 2025 remote from relay.example
hello from pipe
'
run_with_input "$PIPE_INPUT" "$RMAIL_BIN" first@example.test second,third@example.test '<already@wrapped>'
assert_status "pipe happy status" 0 "$LAST_STATUS"
assert_empty "pipe happy stdout" "$LAST_STDOUT"
assert_empty "pipe happy stderr" "$LAST_STDERR"
assert_eq "pipe sendmail argv" "$MOCK_SENDMAIL_BIN
-G
-oee
-odi
-oi
-pUUCP:host1!host2.UUCP
-fhost1!host2!relay.example!bob
first@example.test
<second,third@example.test>
<already@wrapped>" "$(read_file "$SENDMAIL_LOG")"
assert_eq "pipe sendmail input" "
hello from pipe" "$(read_file "$SENDMAIL_INPUT")"
REGULAR_INPUT="$WORKDIR/regular-input"
cat >"$REGULAR_INPUT" <<'EOF'
From charlie Tue Jan 1 00:00:00 2025 remote from mailhub
hello from regular file
EOF
run_with_regular_file "$REGULAR_INPUT" "$RMAIL_BIN" -D LINUX target@example.test
assert_status "regular happy status" 0 "$LAST_STATUS"
assert_empty "regular happy stdout" "$LAST_STDOUT"
assert_empty "regular happy stderr" "$LAST_STDERR"
assert_eq "regular sendmail argv" "$MOCK_SENDMAIL_BIN
-G
-oee
-odi
-oi
-pLINUX:mailhub.LINUX
-fmailhub!charlie
target@example.test" "$(read_file "$SENDMAIL_LOG")"
assert_eq "regular sendmail input" "
hello from regular file" "$(read_file "$SENDMAIL_INPUT")"
DEBUG_INPUT='From user Tue Jan 1 00:00:00 2025 remote from relay
debug body
'
run_with_input "$DEBUG_INPUT" "$RMAIL_BIN" -T user@example.test
assert_status "debug status" 0 "$LAST_STATUS"
assert_empty "debug stdout" "$LAST_STDOUT"
assert_contains "debug stderr remote" "$LAST_STDERR" "remote from: relay"
assert_contains "debug stderr from_sys" "$LAST_STDERR" "from_sys: relay"
assert_contains "debug stderr from_path" "$LAST_STDERR" "from_path: relay!"
assert_contains "debug stderr from_user" "$LAST_STDERR" "from_user: user"
assert_contains "debug stderr args" "$LAST_STDERR" "Sendmail arguments:"
export RMAIL_SENDMAIL_EXIT=23
run_with_input 'From user Tue Jan 1 00:00:00 2025\n\nbody\n' "$RMAIL_BIN" user@example.test
assert_status "sendmail exit status propagation" 23 "$LAST_STATUS"
assert_empty "sendmail exit stdout" "$LAST_STDOUT"
assert_contains "sendmail exit stderr" "$LAST_STDERR" "terminated with 23 (non-zero) status"
unset RMAIL_SENDMAIL_EXIT
export RMAIL_SENDMAIL="$WORKDIR/missing-sendmail"
run_with_input 'From user Tue Jan 1 00:00:00 2025\n\nbody\n' "$RMAIL_BIN" user@example.test
assert_status "missing sendmail status" "$EX_UNAVAILABLE" "$LAST_STATUS"
assert_empty "missing sendmail stdout" "$LAST_STDOUT"
assert_contains "missing sendmail stderr" "$LAST_STDERR" "$WORKDIR/missing-sendmail"
printf '%s\n' "PASS"
|