Blob


1 #!/bin/sh
3 set -e
5 if [ "${SKIP_RUNTIME_TESTS:-0}" -eq 1 ]; then
6 echo
7 echo "======================"
8 echo "runtime tests skipped!"
9 echo "======================"
10 echo
11 exit 0
12 fi
14 ggflags=
16 port=10965
18 config_common="
19 ipv6 off
20 port $port
21 "
23 # usage: config <global config> <stuff for localhost>
24 # generates a configuration file reg.conf
25 config() {
26 cat <<EOF > reg.conf
27 $config_common
28 $1
29 server "localhost" {
30 cert "$PWD/cert.pem"
31 key "$PWD/key.pem"
32 root "$PWD/testdata"
33 $2
34 }
35 EOF
36 }
38 checkconf() {
39 ./../gmid -n -c reg.conf
40 }
42 # usage: get <path>
43 # return the body of the request on stdout
44 get() {
45 ./gg -T30 -b $ggflags "gemini://localhost:10965/$1"
46 }
48 # usage: head <path>
49 # return the meta response line on stdout
50 head() {
51 ./gg -T30 -h $ggflags "gemini://localhost:10965/$1"
52 }
54 # usage: raw <path>
55 # return both header and body
56 raw() {
57 ./gg -T30 $ggflags "gemini://localhost:10965/$1"
58 }
60 run() {
61 ./../gmid -f -c reg.conf &
62 pid=$!
63 # give gmid time to bind the port, otherwise we end up
64 # executing gg when gmid isn't ready yet.
65 sleep 1
66 }
68 # usage: check [exit-message]
69 # check if gmid is still running
70 check() {
71 if ! ps $pid >/dev/null; then
72 echo ${1:-"gmid crashed?"}
73 exit 1
74 fi
75 }
77 restart() {
78 kill -HUP $pid
79 sleep 1
80 }
82 # quit gmid
83 quit() {
84 kill $pid || true
85 wait || true
86 }
88 count() {
89 wc -l | xargs
90 }
92 # usage: eq a b errmsg
93 # if a and b aren't equal strings, exit with errmsg
94 eq() {
95 if ! [ "$1" = "$2" ]; then
96 echo "$3: \"$1\" not equal \"$2\""
97 exit 1
98 fi
99 }
101 onexit() {
102 rm -f bigfile bigfile.sha
103 quit
106 # configless tests
108 ./../gmid -p $port -H localhost -d . testdata &
109 pid=$!
110 sleep 1
112 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
113 eq "$(get /)" "# hello world$ln" "Unexpected body for /"
114 echo OK GET / in configless mode
115 quit
117 # daemon tests
119 trap 'onexit' INT TERM EXIT
121 endl=`printf "\r\n"`
122 lf=`echo`
124 config "" ""
125 checkconf
126 run
128 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
129 eq "$(get /)" "# hello world$ln" "Unexpected body for /"
130 echo OK GET /
132 eq "$(head /foo)" "51 not found" "Unexpected head /foo"
133 eq "$(get /foo)" "" "Unexpected body /foo"
134 echo OK GET /foo
136 # should redirect if asked for a directory but without the trailing /
137 eq "$(head /dir)" "30 /dir/" "Unexpected redirect for /dir"
138 eq "$(get /dir)" "" "Unexpected body for redirect"
139 echo OK GET /dir
141 # 51 for a directory without index.gmi
142 eq "$(head /dir/)" "51 not found" "Unexpected head for /"
143 eq "$(get /dir/)" "" "Unexpected body for error"
144 echo OK GET /dir/
146 eq "$(head /dir/foo.gmi)" "20 text/gemini" "Unexpected head for /dir/foo.gmi"
147 eq "$(get /dir/foo.gmi)" "# hello world$ln" "Unexpected body for /dir/foo.gmi"
148 echo OK GET /dir/foo.gmi
150 # try a big file
151 eq "$(head /bigfile)" "20 application/octet-stream" "Unexpected head for /bigfile"
152 get /bigfile > bigfile
153 ./sha bigfile bigfile.sha
154 eq "$(cat bigfile.sha)" "$(cat testdata/bigfile.sha)" "Unexpected sha for /bigfile"
155 echo OK GET /bigfile
157 # shouldn't be executing cgi scripts
158 eq "$(head /hello)" "20 application/octet-stream" "Unexpected head for /hello"
159 echo OK GET /hello
161 check "should be running"
163 # try with custom mime
164 config 'map "text/x-funny-text" to-ext "gmi"' 'default type "application/x-trash"'
165 checkconf
166 restart
168 eq "$(head /)" "20 text/x-funny-text" "Unexpected head for /"
169 echo OK GET / with custom mime
171 eq "$(head /hello)" "20 application/x-trash" "Unexpected head for /hello"
172 echo OK GET /hello with custom mime
174 check "should be running"
176 # try with custom lang
177 config '' 'lang "it"'
178 checkconf
179 restart
181 eq "$(head /)" "20 text/gemini; lang=it" "Unexpected head for /"
182 echo OK GET / with custom lang
184 check "should be running"
186 # make sure we can use different lang in different location rules
187 config '' 'lang "it" location "/en/*" { lang "en" } location "/de/*" { lang "de" }'
188 checkconf
189 echo OK parse multiple locations correctly
190 restart
192 # try with CGI scripts
193 config '' 'cgi "*"'
194 checkconf
195 restart
197 eq "$(head /hello)" "20 text/gemini" "Unexpected head for /hello"
198 eq "$(get /hello)" "# hello world$ln" "Unexpected body for /hello"
199 echo OK GET /hello with cgi
201 eq "$(head /slow)" "20 text/gemini" "Unexpected head for /slow"
202 eq "$(get /slow)" "# hello world$ln" "Unexpected body for /slow"
203 echo OK GET /slow with cgi
205 eq "$(head /err)" "42 CGI error" "Unexpected head for /err"
206 eq "$(get /err)" "" "Unexpected body for /err"
207 echo OK GET /err with cgi
209 eq "$(raw /invalid | wc -c | xargs)" 2048 "Unexpected body for /invalid"
210 echo OK GET /invalid with cgi
212 eq "$(raw /max-length-reply | wc -c | xargs)" 1029 "Unexpected header for /max-length-reply"
213 echo OK GET /max-length-reply with cgi
215 # try a big file
216 eq "$(head /serve-bigfile)" "20 application/octet-stream" "Unexpected head for /serve-bigfile"
217 get /bigfile > bigfile
218 ./sha bigfile bigfile.sha
219 eq "$(cat bigfile.sha)" "$(cat testdata/bigfile.sha)" "Unexpected sha for /serve-bigfile"
220 echo OK GET /serve-bigfile with cgi
222 # ensure we split the query correctly
223 eq "$(get /env | awk /^-/ | count)" 1 "Unexpected number of arguments"
224 eq "$(get /env?foo | awk /^-/ | count)" 2 "Unexpected number of arguments"
225 eq "$(get /env?foo+bar | awk /^-/ | count)" 3 "Unexpected number of arguments"
226 eq "$(get /env?foo+bar=5 | awk /^-/ | count)" 1 "Unexpected number of arguments"
227 eq "$(get /env?foo+bar%3d5 | awk /^-/ | count)" 3 "Unexpected number of arguments"
229 check "should be running"
231 config '' 'index "foo.gmi"'
232 checkconf
233 restart
235 eq "$(head /dir/)" "20 text/gemini" "Unexpected head for /"
236 eq "$(get /dir/)" "# hello world$ln" "Unexpected body for error"
237 echo OK GET /dir/ with custom index
239 check "should be running"
241 config '' 'location "/dir/*" { default type "text/plain" index "hello" }'
242 checkconf
243 restart
245 eq "$(head /dir/hello)" "20 text/plain" "Unexpected head for /"
246 echo OK GET /dir/hello with location and default type
248 eq "$(head /dir/)" "20 text/plain" "Unexpected head for /dir/"
249 eq "$(get /dir/|tail -1)" 'echo "# hello world"' "Unexpected body for /dir/"
250 echo OK GET /dir/ with location and custom index
252 check "should be running"
254 config '' 'location "/dir/*" { auto index on }'
255 checkconf
256 restart
258 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
259 eq "$(get /)" "# hello world$ln" "Unexpected body for /"
260 echo OK GET / with auto index
262 eq "$(head /dir)" "30 /dir/" "Unexpected head for /dir"
263 eq "$(head /dir/)" "20 text/gemini" "Unexpected head for /dir/"
264 eq "$(get /dir/|wc -l|xargs)" "5" "Unexpected body for /dir/"
265 echo OK GET /dir/ with auto index on
267 check "should be running"
269 # test block return and strip
271 config '' 'location "*" { block }'
272 checkconf
273 restart
275 eq "$(head /)" "40 temporary failure" "Unexpected head for /"
276 eq "$(get /)" "" "Unexpected body for /"
277 echo OK GET / with block
279 eq "$(head /nonexists)" "40 temporary failure" "Unexpected head for /nonexists"
280 eq "$(get /nonexists)" "" "Unexpected body for /nonexists"
281 echo OK GET /nonexists with block
283 check "should be running"
285 config '' '
286 location "/dir" {
287 strip 1
288 block return 40 "%% %p %q %P %N test"
290 location "*" {
291 strip 99
292 block return 40 "%% %p %q %P %N test"
293 }'
294 checkconf
295 restart
297 eq "$(head /dir/foo.gmi)" "40 % /foo.gmi 10965 localhost test"
298 echo OK GET /dir/foo.gmi with strip and block
300 eq "$(head /bigfile)" "40 % / 10965 localhost test"
301 echo OK GET /bigfile with strip and block
303 check "should be running"
305 # test the entrypoint
307 config '' 'entrypoint "/env"'
308 checkconf
309 restart
311 eq "$(head /foo/bar)" "20 text/plain; lang=en" "Unknown head for /foo/bar"
312 eq "$(get /foo/bar|grep PATH_INFO)" "PATH_INFO=/foo/bar" "Unexpected PATH_INFO"
313 echo OK GET /foo/bar with entrypoint
315 # test with require ca
317 config '' 'require client ca "'$PWD'/testca.pem"'
318 checkconf
319 restart
321 eq "$(head /)" "60 client certificate required" "Unexpected head for /"
322 echo OK GET / without client certificate
324 ggflags="-C valid.crt -K valid.key"
325 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
326 echo OK GET / with valid client certificate
328 ggflags="-C invalid.cert.pem -K invalid.key.pem"
329 eq "$(head /)" "61 certificate not authorised" "Unexpected head for /"
330 echo OK GET / with invalid client certificate
332 ggflags=''
335 # test with root inside a location
337 config '' 'location "/foo/*" { root "'$PWD'/testdata" strip 1 }'
338 checkconf
339 restart
341 eq "$(head /foo)" "51 not found" "Unexpected head for /foo"
342 eq "$(head /foo/)" "20 text/gemini" "Unexpected head for /foo/"
343 echo OK /foo and /foo/ with root inside location
345 # how to match both /foo and /foo/*
346 config '' '
347 location "/foo" { block return 31 "%p/" }
348 location "/foo/*" { root "'$PWD'/testdata" strip 1 }
350 checkconf
351 restart
353 eq "$(head /foo)" "31 /foo/" "Unexpected head for /foo"
354 eq "$(head /foo/)" "20 text/gemini" "Unexpected head for /foo/"
355 echo OK /foo and /foo/ with root inside location
357 # test with fastcgi
359 # NB: the fcgi spawn is NOT supported outside of this test suite
361 config 'prefork 1' 'fastcgi spawn "'$PWD'/fcgi-test"'
362 checkconf
363 restart
365 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
366 eq "$(get /)" "# Hello, world!" "Unexpected body for /"
367 echo OK GET / with fastcgi
369 # test macro expansion
371 cat <<EOF > reg.conf
372 pwd = "$PWD"
373 $config_common
375 server "localhost" {
376 # the quoting of \$ is for sh
377 cert \$pwd "/cert.pem"
378 key \$pwd "/key.pem"
379 root \$pwd "/testdata"
381 EOF
382 checkconf
383 restart
385 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
386 eq "$(get /)" "# hello world$ln" "Unexpected body for /"
387 echo OK GET / with macro expansion