aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--regress/Makefile1
-rw-r--r--regress/lib.sh185
-rwxr-xr-xregress/runtime415
-rw-r--r--regress/tests.sh305
5 files changed, 525 insertions, 382 deletions
diff --git a/.gitignore b/.gitignore
index 89f482a..e4a5ff4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,4 @@ regress/iri_test
regress/puny-test
regress/*.o
regress/gg
+regress/gmid.pid
diff --git a/regress/Makefile b/regress/Makefile
index 0efddad..5b2d29b 100644
--- a/regress/Makefile
+++ b/regress/Makefile
@@ -71,6 +71,7 @@ clean:
rm -f localhost.cert.pem localhost.key.pem
rm -f testca.* valid.csr valid.key valid.crt invalid.*pem
rm -rf testdata fill-file puny-test gg fcgi-test
+ rm -f gmid.pid
testdata: fill-file
mkdir testdata
diff --git a/regress/lib.sh b/regress/lib.sh
new file mode 100644
index 0000000..afee6f8
--- /dev/null
+++ b/regress/lib.sh
@@ -0,0 +1,185 @@
+failed=
+
+gg="./gg"
+gmid="./../gmid"
+current_test=
+
+run_test() {
+ ggflags=
+ port=10965
+ config_common="
+ipv6 off
+port $port
+"
+ hdr=
+ body=
+ dont_check=no
+
+ current_test=$1
+ rm -f reg.conf
+
+ if ! $1; then
+ echo "$1 failed"
+ failed="$failed $1"
+ else
+ echo "$1 passed"
+ fi
+
+ if [ "$dont_check" != 'no' ]; then
+ return
+ fi
+
+ if ! check; then
+ echo "gmid crashed?"
+ failed="$failed $1"
+ fi
+}
+
+# usage: gen_config <global config> <server config>
+# generates a configuration file reg.conf
+gen_config() {
+ cat <<EOF > reg.conf
+$config_common
+$1
+server "localhost" {
+ cert "$PWD/cert.pem"
+ key "$PWD/key.pem"
+ root "$PWD/testdata"
+ $2
+}
+EOF
+ if ! checkconf; then
+ echo "failed to parse the config" >&2
+ return 1
+ fi
+}
+
+checkconf() {
+ $gmid -n -c reg.conf >/dev/null
+}
+
+# usage: setup_simple_test <global config> <server config>
+# generates a configuration file with `gen_config', validates it and
+# launches the daemon
+setup_simple_test() {
+ gen_config "$1" "$2"
+ run
+}
+
+# usage: get <path>
+# return the body of the request on stdout
+get() {
+ $gg -T30 -b $ggflags "gemini://localhost:10965/$1"
+}
+
+# usage: head <path>
+# return the meta response line on stdout
+head() {
+ $gg -T30 -h $ggflags "gemini://localhost:10965/$1"
+}
+
+# usage: raw <path>
+# return both header and body
+raw() {
+ $gg -T30 $ggflags "gemini://localhost:10965/$1"
+}
+
+# usage: fetch <path>
+# fetches the header and the body. They're returned in $hdr and
+# $body.
+fetch() {
+ if ! hdr="$(head $1)" || ! body="$(get $1)"; then
+ return 1
+ fi
+}
+
+# usage: fetch_hdr <path>
+# fetches the header into $hdr
+fetch_hdr() {
+ hdr="$(head $1)"
+ body=""
+}
+
+# usage: check_reply header body
+# checks that $hdr and $body are equal to the given strings
+check_reply() {
+ if [ "$hdr" != "$1" ]; then
+ echo "Header mismatch" >&2
+ echo "wants : $1" >&2
+ echo "got : $hdr" >&2
+ return 1
+ fi
+
+ if [ "$body" != "$2" ]; then
+ echo "Body mismatch" >&2
+ echo "wants : $1" >&2
+ echo "got : $body" >&2
+ return 1
+ fi
+}
+
+run() {
+ if check; then
+ kill -HUP "$(cat gmid.pid)"
+ sleep 1
+ return
+ fi
+
+ $gmid -P gmid.pid -c reg.conf
+
+ # give gmid time to bind the port, otherwise we end up
+ # executing gg when gmid isn't ready yet.
+ sleep 1
+}
+
+check() {
+ if [ ! -f gmid.pid ]; then
+ return 1
+ fi
+
+ pid="$(cat gmid.pid || true)"
+ if [ "$pid" == "" ]; then
+ return 1
+ fi
+
+ # remember: we're running under ``set -e''
+ if ps $pid >/dev/null; then
+ return 0
+ fi
+
+ return 1
+}
+
+# usage: sha in out
+# writes the sha256 of `in' to `out'
+sha() {
+ if which sha256 >/dev/null 2>&1; then
+ sha256 < "$1" > "$2"
+ return $?
+ fi
+
+ if which sha256sum >/dev/null 2>&1; then
+ sha256sum "$1" | awk '{print $1}' > "$2"
+ return $?
+ fi
+
+ echo "No sha binary found" >&2
+ exit 1
+}
+
+count() {
+ wc -l | xargs
+}
+
+quit() {
+ pid="$(cat gmid.pid || true)"
+ if [ "$pid" != "" ]; then
+ kill $pid || true
+ wait || true
+ fi
+}
+
+onexit() {
+ rm -f bigfile bigfile.sha
+ quit
+}
diff --git a/regress/runtime b/regress/runtime
index 7566a1a..f34ff7d 100755
--- a/regress/runtime
+++ b/regress/runtime
@@ -1,7 +1,5 @@
#!/bin/sh
-set -e
-
if [ "${SKIP_RUNTIME_TESTS:-0}" -eq 1 ]; then
echo
echo "======================"
@@ -11,387 +9,40 @@ if [ "${SKIP_RUNTIME_TESTS:-0}" -eq 1 ]; then
exit 0
fi
-ggflags=
-
-port=10965
-
-config_common="
-ipv6 off
-port $port
-"
-
-# usage: config <global config> <stuff for localhost>
-# generates a configuration file reg.conf
-config() {
- cat <<EOF > reg.conf
-$config_common
-$1
-server "localhost" {
- cert "$PWD/cert.pem"
- key "$PWD/key.pem"
- root "$PWD/testdata"
- $2
-}
-EOF
-}
-
-checkconf() {
- ./../gmid -n -c reg.conf
-}
-
-# usage: get <path>
-# return the body of the request on stdout
-get() {
- ./gg -T30 -b $ggflags "gemini://localhost:10965/$1"
-}
-
-# usage: head <path>
-# return the meta response line on stdout
-head() {
- ./gg -T30 -h $ggflags "gemini://localhost:10965/$1"
-}
-
-# usage: raw <path>
-# return both header and body
-raw() {
- ./gg -T30 $ggflags "gemini://localhost:10965/$1"
-}
-
-run() {
- ./../gmid -f -c reg.conf &
- pid=$!
- # give gmid time to bind the port, otherwise we end up
- # executing gg when gmid isn't ready yet.
- sleep 1
-}
-
-# usage: check [exit-message]
-# check if gmid is still running
-check() {
- if ! ps $pid >/dev/null; then
- echo ${1:-"gmid crashed?"}
- exit 1
- fi
-}
-
-restart() {
- kill -HUP $pid
- sleep 1
-}
-
-# quit gmid
-quit() {
- kill $pid || true
- wait || true
-}
+rm -f gmid.pid
-count() {
- wc -l | xargs
-}
-
-# usage: eq a b errmsg
-# if a and b aren't equal strings, exit with errmsg
-eq() {
- if ! [ "$1" = "$2" ]; then
- echo "$3: \"$1\" not equal \"$2\""
- exit 1
- fi
-}
-
-onexit() {
- rm -f bigfile bigfile.sha
- quit
-}
-
-# configless tests
-
-./../gmid -p $port -H localhost -d . testdata &
-pid=$!
-sleep 1
-
-eq "$(head /)" "20 text/gemini" "Unexpected head for /"
-eq "$(get /)" "# hello world$ln" "Unexpected body for /"
-echo OK GET / in configless mode
-quit
-
-# daemon tests
+. ./lib.sh
+. ./tests.sh
trap 'onexit' INT TERM EXIT
-endl=`printf "\r\n"`
-lf=`echo`
-
-config "" ""
-checkconf
-run
-
-eq "$(head /)" "20 text/gemini" "Unexpected head for /"
-eq "$(get /)" "# hello world$ln" "Unexpected body for /"
-echo OK GET /
-
-eq "$(head /foo)" "51 not found" "Unexpected head /foo"
-eq "$(get /foo)" "" "Unexpected body /foo"
-echo OK GET /foo
-
-# should redirect if asked for a directory but without the trailing /
-eq "$(head /dir)" "30 /dir/" "Unexpected redirect for /dir"
-eq "$(get /dir)" "" "Unexpected body for redirect"
-echo OK GET /dir
-
-# 51 for a directory without index.gmi
-eq "$(head /dir/)" "51 not found" "Unexpected head for /"
-eq "$(get /dir/)" "" "Unexpected body for error"
-echo OK GET /dir/
-
-eq "$(head /dir/foo.gmi)" "20 text/gemini" "Unexpected head for /dir/foo.gmi"
-eq "$(get /dir/foo.gmi)" "# hello world$ln" "Unexpected body for /dir/foo.gmi"
-echo OK GET /dir/foo.gmi
-
-# try a big file
-eq "$(head /bigfile)" "20 application/octet-stream" "Unexpected head for /bigfile"
-get /bigfile > bigfile
-./sha bigfile bigfile.sha
-eq "$(cat bigfile.sha)" "$(cat testdata/bigfile.sha)" "Unexpected sha for /bigfile"
-echo OK GET /bigfile
-
-# shouldn't be executing cgi scripts
-eq "$(head /hello)" "20 application/octet-stream" "Unexpected head for /hello"
-echo OK GET /hello
-
-check "should be running"
-
-# try with custom mime
-config 'map "text/x-funny-text" to-ext "gmi"' 'default type "application/x-trash"'
-checkconf
-restart
-
-eq "$(head /)" "20 text/x-funny-text" "Unexpected head for /"
-echo OK GET / with custom mime
-
-eq "$(head /hello)" "20 application/x-trash" "Unexpected head for /hello"
-echo OK GET /hello with custom mime
-
-check "should be running"
-
-# try with custom lang
-config '' 'lang "it"'
-checkconf
-restart
-
-eq "$(head /)" "20 text/gemini;lang=it" "Unexpected head for /"
-echo OK GET / with custom lang
-
-check "should be running"
-
-# make sure we can use different lang in different location rules
-config '' 'lang "it" location "/en/*" { lang "en" } location "/de/*" { lang "de" }'
-checkconf
-echo OK parse multiple locations correctly
-restart
-
-# try with CGI scripts
-config '' 'cgi "*"'
-checkconf
-restart
-
-eq "$(head /hello)" "20 text/gemini" "Unexpected head for /hello"
-eq "$(get /hello)" "# hello world$ln" "Unexpected body for /hello"
-echo OK GET /hello with cgi
-
-eq "$(head /slow)" "20 text/gemini" "Unexpected head for /slow"
-eq "$(get /slow)" "# hello world$ln" "Unexpected body for /slow"
-echo OK GET /slow with cgi
-
-eq "$(head /err)" "42 CGI error" "Unexpected head for /err"
-eq "$(get /err)" "" "Unexpected body for /err"
-echo OK GET /err with cgi
-
-#eq "$(raw /invalid | wc -c | xargs)" 2048 "Unexpected body for /invalid"
-#echo OK GET /invalid with cgi
-
-eq "$(raw /max-length-reply | wc -c | xargs)" 1029 "Unexpected header for /max-length-reply"
-echo OK GET /max-length-reply with cgi
-
-# try a big file
-eq "$(head /serve-bigfile)" "20 application/octet-stream" "Unexpected head for /serve-bigfile"
-get /bigfile > bigfile
-./sha bigfile bigfile.sha
-eq "$(cat bigfile.sha)" "$(cat testdata/bigfile.sha)" "Unexpected sha for /serve-bigfile"
-echo OK GET /serve-bigfile with cgi
-
-# ensure we split the query correctly
-eq "$(get /env | awk /^-/ | count)" 1 "Unexpected number of arguments"
-eq "$(get /env?foo | awk /^-/ | count)" 2 "Unexpected number of arguments"
-eq "$(get /env?foo+bar | awk /^-/ | count)" 3 "Unexpected number of arguments"
-eq "$(get /env?foo+bar=5 | awk /^-/ | count)" 1 "Unexpected number of arguments"
-eq "$(get /env?foo+bar%3d5 | awk /^-/ | count)" 3 "Unexpected number of arguments"
-
-check "should be running"
-
-config '' 'index "foo.gmi"'
-checkconf
-restart
-
-eq "$(head /dir/)" "20 text/gemini" "Unexpected head for /"
-eq "$(get /dir/)" "# hello world$ln" "Unexpected body for error"
-echo OK GET /dir/ with custom index
-
-check "should be running"
-
-config '' 'location "/dir/*" { default type "text/plain" index "hello" }'
-checkconf
-restart
-
-eq "$(head /dir/hello)" "20 text/plain" "Unexpected head for /"
-echo OK GET /dir/hello with location and default type
-
-eq "$(head /dir/)" "20 text/plain" "Unexpected head for /dir/"
-eq "$(get /dir/|tail -1)" 'echo "# hello world"' "Unexpected body for /dir/"
-echo OK GET /dir/ with location and custom index
-
-check "should be running"
-
-config '' 'location "/dir/*" { auto index on }'
-checkconf
-restart
-
-eq "$(head /)" "20 text/gemini" "Unexpected head for /"
-eq "$(get /)" "# hello world$ln" "Unexpected body for /"
-echo OK GET / with auto index
-
-eq "$(head /dir)" "30 /dir/" "Unexpected head for /dir"
-eq "$(head /dir/)" "20 text/gemini" "Unexpected head for /dir/"
-eq "$(get /dir/|wc -l|xargs)" "5" "Unexpected body for /dir/"
-echo OK GET /dir/ with auto index on
-
-check "should be running"
-
-# test block return and strip
-
-config '' 'location "*" { block }'
-checkconf
-restart
-
-eq "$(head /)" "40 temporary failure" "Unexpected head for /"
-eq "$(get /)" "" "Unexpected body for /"
-echo OK GET / with block
-
-eq "$(head /nonexists)" "40 temporary failure" "Unexpected head for /nonexists"
-eq "$(get /nonexists)" "" "Unexpected body for /nonexists"
-echo OK GET /nonexists with block
-
-check "should be running"
-
-config '' '
-location "/dir" {
- strip 1
- block return 40 "%% %p %q %P %N test"
-}
-location "*" {
- strip 99
- block return 40 "%% %p %q %P %N test"
-}'
-checkconf
-restart
-
-eq "$(head /dir/foo.gmi)" "40 % /foo.gmi 10965 localhost test"
-echo OK GET /dir/foo.gmi with strip and block
-
-eq "$(head /bigfile)" "40 % / 10965 localhost test"
-echo OK GET /bigfile with strip and block
-
-check "should be running"
-
-# test the entrypoint
-
-config '' 'entrypoint "/env"'
-checkconf
-restart
-
-eq "$(head /foo/bar)" "20 text/plain; lang=en" "Unknown head for /foo/bar"
-eq "$(get /foo/bar|grep PATH_INFO)" "PATH_INFO=/foo/bar" "Unexpected PATH_INFO"
-echo OK GET /foo/bar with entrypoint
-
-# test with require ca
-
-config '' 'require client ca "'$PWD'/testca.pem"'
-checkconf
-restart
-
-eq "$(head /)" "60 client certificate required" "Unexpected head for /"
-echo OK GET / without client certificate
-
-ggflags="-C valid.crt -K valid.key"
-eq "$(head /)" "20 text/gemini" "Unexpected head for /"
-echo OK GET / with valid client certificate
-
-ggflags="-C invalid.cert.pem -K invalid.key.pem"
-eq "$(head /)" "61 certificate not authorised" "Unexpected head for /"
-echo OK GET / with invalid client certificate
-
-ggflags=''
-
-
-# test with root inside a location
-
-config '' 'location "/foo/*" { root "'$PWD'/testdata" strip 1 }'
-checkconf
-restart
-
-eq "$(head /foo)" "51 not found" "Unexpected head for /foo"
-eq "$(head /foo/)" "20 text/gemini" "Unexpected head for /foo/"
-echo OK /foo and /foo/ with root inside location
-
-# how to match both /foo and /foo/*
-config '' '
- location "/foo" { block return 31 "%p/" }
- location "/foo/*" { root "'$PWD'/testdata" strip 1 }
-'
-checkconf
-restart
-
-eq "$(head /foo)" "31 /foo/" "Unexpected head for /foo"
-eq "$(head /foo/)" "20 text/gemini" "Unexpected head for /foo/"
-echo OK /foo and /foo/ with root inside location
-
-# test with fastcgi
-
-# NB: the fcgi spawn is NOT supported outside of this test suite
-
-config 'prefork 1' 'fastcgi spawn "'$PWD'/fcgi-test"'
-checkconf
-restart
-
-eq "$(head /)" "20 text/gemini" "Unexpected head for /"
-eq "$(get /)" "# Hello, world!" "Unexpected body for /"
-echo OK GET / with fastcgi
-
-# test macro expansion
-
-cat <<EOF > reg.conf
-pwd = "$PWD"
-$config_common
-
-server "localhost" {
- # the quoting of \$ is for sh
- cert \$pwd "/cert.pem"
- key \$pwd "/key.pem"
- root \$pwd "/testdata"
-}
-EOF
-checkconf
-restart
-
-eq "$(head /)" "20 text/gemini" "Unexpected head for /"
-eq "$(get /)" "# hello world$ln" "Unexpected body for /"
-echo OK GET / with macro expansion
-
-
-# 1.7.4 bugfix: check_for_cgi goes out-of-bound processing a string
-# that doesn't contain a '/'
-config '' 'cgi "*"'
-checkconf
-restart
-
-eq "$(head /favicon.txt)" "51 not found" "Unexpected head for /"
-echo OK GET /favicon.txt with cgi
+run_test test_configless_mode
+run_test test_static_files
+run_test test_directory_redirect
+run_test test_serve_big_files
+run_test test_dont_execute_scripts
+run_test test_custom_mime
+run_test test_default_type
+run_test test_custom_lang
+run_test test_parse_custom_lang_per_location
+run_test test_cgi_scripts
+run_test test_cgi_big_replies
+run_test test_cgi_split_query
+run_test test_custom_index
+run_test test_custom_index_default_type_per_location
+run_test test_auto_index
+run_test test_block
+run_test test_block_return_fmt
+run_test test_entrypoint
+run_test test_require_client_ca
+run_test test_root_inside_location
+run_test test_root_inside_location_with_redirect
+run_test test_fastcgi
+run_test test_macro_expansion
+run_test test_174_bugfix
+
+if [ "$failed" != "" ]; then
+ echo
+ echo "failed tests:$failed"
+ exit 1
+fi
diff --git a/regress/tests.sh b/regress/tests.sh
new file mode 100644
index 0000000..c01013e
--- /dev/null
+++ b/regress/tests.sh
@@ -0,0 +1,305 @@
+test_configless_mode() {
+ dont_check=yes
+
+ $gmid -p $port -H localhost -d . testdata &
+ pid=$!
+ sleep 1
+
+ fetch /
+ kill $pid
+ check_reply "20 text/gemini" "# hello world" || return 1
+}
+
+test_static_files() {
+ setup_simple_test
+
+ fetch /
+ check_reply "20 text/gemini" "# hello world" || return 1
+
+ fetch /foo
+ check_reply "51 not found" || return 1
+
+ fetch /dir/foo.gmi
+ check_reply "20 text/gemini" "# hello world" || return 1
+}
+
+test_directory_redirect() {
+ setup_simple_test
+
+ fetch /dir
+ check_reply "30 /dir/" || return 1
+
+ fetch /dir/
+ check_reply "51 not found" || return 1
+}
+
+test_serve_big_files() {
+ setup_simple_test
+
+ hdr="$(head /bigfile)"
+ get /bigfile > bigfile
+ sha bigfile bigfile.sha
+ body="$(cat bigfile.sha)"
+
+ check_reply "20 application/octet-stream" "$(cat testdata/bigfile.sha)"
+}
+
+test_dont_execute_scripts() {
+ setup_simple_test
+
+ fetch_hdr /hello
+ check_reply "20 application/octet-stream" "" || return 1
+}
+
+test_custom_mime() {
+ setup_simple_test 'map "text/x-funny" to-ext "gmi"' ''
+
+ fetch_hdr /
+ check_reply "20 text/x-funny"
+}
+
+test_default_type() {
+ setup_simple_test '' 'default type "application/x-foo"'
+
+ fetch_hdr /hello
+ check_reply "20 application/x-foo"
+}
+
+test_custom_lang() {
+ setup_simple_test '' 'lang it'
+
+ fetch_hdr /
+ check_reply "20 text/gemini;lang=it"
+}
+
+test_parse_custom_lang_per_location() {
+ setup_simple_test '' \
+ 'lang it location "/en/*" {lang en} location "/de/*" {lang de}'
+ # can parse multiple locations
+}
+
+test_cgi_scripts() {
+ setup_simple_test '' 'cgi "*"'
+
+ fetch /hello
+ check_reply "20 text/gemini" "# hello world" || return 1
+
+ fetch /slow
+ check_reply "20 text/gemini" "# hello world" || return 1
+
+ fetch /err
+ check_reply "42 CGI error" || return 1
+
+ fetch /invalid
+ check_reply "42 CGI error" || return 1
+}
+
+test_cgi_big_replies() {
+ setup_simple_test '' 'cgi "*"'
+
+ hdr="$(head /serve-bigfile)"
+ get /bigfile > bigfile
+ sha bigfile bigfile.sha
+ body="$(cat bigfile.sha)"
+ check_reply "20 application/octet-stream" "$(cat testdata/bigfile.sha)"
+}
+
+test_cgi_split_query() {
+ setup_simple_test '' 'cgi "*"'
+
+ for s in "1" "2 ?foo" "3 ?foo+bar" "1 ?foo+bar=5" "3 ?foo+bar%3d5"; do
+ exp="$(echo $s | sed 's/ .*//')"
+ qry="$(echo $s | sed 's/^..//')"
+
+ if [ "$exp" = "$qry" ]; then
+ # the "1" case yields exp == qry
+ qry=''
+ fi
+
+ url="/env$qry"
+
+ n="$(get "$url" | awk /^-/ | count)"
+ if [ $? -ne 0 ]; then
+ echo "failed to get /$url"
+ return 1
+ fi
+
+ if [ "$n" -ne $exp ]; then
+ echo "Unexpected number of args"
+ echo "want : $exp"
+ echo "got : $n"
+ return 1
+ fi
+ done
+}
+
+test_custom_index() {
+ setup_simple_test '' 'index "foo.gmi"'
+
+ fetch /dir/
+ check_reply "20 text/gemini" "# hello world"
+}
+
+test_custom_index_default_type_per_location() {
+ setup_simple_test '' 'location "/dir/*" { default type "text/plain" index "hello" }'
+
+ fetch /dir/
+ check_reply "20 text/plain" "$(cat hello)"
+}
+
+test_auto_index() {
+ setup_simple_test '' 'location "/dir/*" { auto index on }'
+
+ fetch /
+ check_reply "20 text/gemini" "# hello world" || return 1
+
+ fetch_hdr /dir
+ check_reply "30 /dir/" || return 1
+
+ fetch_hdr /dir/
+ check_reply "20 text/gemini"
+
+ # we expect 5 lines from the auto index
+
+ body="$(get /dir/ | count)"
+ if [ $? -ne 0 ]; then
+ echo 'failed to get /dir/'
+ return 1
+ fi
+
+ if [ "$body" -ne 5 ]; then
+ echo "expected five lines from the auto index, got $body"
+ return 1
+ fi
+}
+
+test_block() {
+ setup_simple_test '' 'location "*" { block }'
+
+ fetch /
+ check_reply "40 temporary failure" || return 1
+
+ fetch /nonexists
+ check_reply "40 temporary failure" || return 1
+}
+
+test_block_return_fmt() {
+ setup_simple_test '' '
+location "/dir" {
+ strip 1
+ block return 40 "%% %p %q %P %N test"
+}
+location "*" {
+ strip 99
+ block return 40 "%% %p %q %P %N test"
+}'
+
+ fetch_hdr /dir/foo.gmi
+ check_reply "40 % /foo.gmi 10965 localhost test" || return 1
+
+ fetch_hdr /bigfile
+ check_reply "40 % / 10965 localhost test" || return 1
+}
+
+test_entrypoint() {
+ setup_simple_test '' 'entrypoint "/env"'
+
+ fetch_hdr /foo/bar
+ check_reply "20 text/plain; lang=en" || return 1
+
+ # TODO: test something similar with plain cgi too
+
+ body="$(get /foo/bar|grep PATH_INFO)"
+ if [ $? -ne 0 ]; then
+ echo "failed to get /foo/bar"
+ return 1
+ fi
+
+ if [ "$body" != "PATH_INFO=/foo/bar" ]; then
+ echo "Invalid PATH_INFO generated"
+ echo "want : PATH_INFO=/foo/bar"
+ echo "got : $body"
+ return 1
+ fi
+}
+
+test_require_client_ca() {
+ setup_simple_test '' 'require client ca "'$PWD'/testca.pem"'
+
+ fetch /
+ check_reply "60 client certificate required" || return 1
+
+ ggflags="-C valid.crt -K valid.key"
+ fetch_hdr /
+ check_reply "20 text/gemini" || return 1
+
+ ggflags="-C invalid.cert.pem -K invalid.key.pem"
+ fetch_hdr /
+ check_reply "61 certificate not authorised" || return 1
+}
+
+test_root_inside_location() {
+ setup_simple_test '' 'location "/foo/*" { root "'$PWD'/testdata" strip 1 }'
+
+ fetch /foo
+ check_reply "51 not found" || return 1
+
+ fetch_hdr /foo/
+ check_reply "20 text/gemini"
+}
+
+test_root_inside_location_with_redirect() {
+ setup_simple_test '' '
+location "/foo" { block return 31 "%p/" }
+location "/foo/*" { root "'$PWD'/testdata" strip 1 }'
+
+ fetch /foo
+ check_reply "31 /foo/" || return 1
+
+ fetch_hdr /foo/
+ check_reply "20 text/gemini"
+}
+
+test_fastcgi() {
+ # XXX: prefork 1 for testing
+ setup_simple_test 'prefork 1' 'fastcgi spawn "'$PWD'/fcgi-test"'
+
+ fetch /
+ check_reply "20 text/gemini" "# Hello, world!"
+}
+
+test_macro_expansion() {
+ cat <<EOF > reg.conf
+pwd = "$PWD"
+$config_common
+
+server "localhost" {
+ # the quoting of \$ is for sh
+ cert \$pwd "/cert.pem"
+ key \$pwd "/key.pem"
+ root \$pwd "/testdata"
+}
+EOF
+
+ if ! checkconf; then
+ echo "failed to parse the config"
+ return 1
+ fi
+
+ run
+
+ fetch /
+ check_reply "20 text/gemini" "# hello world"
+}
+
+# 1.7.4 bugfix: check_for_cgi goes out-of-bound processing a string
+# that doesn't contain a '/'
+test_174_bugfix() {
+ setup_simple_test '' 'cgi "*"'
+
+ # thanks cage :)
+ for i in 0 1 2 3 4 5 6 7 8 9; do
+ fetch /favicon.txt
+ check_reply "51 not found" || return 1
+ done
+}