commit 176179b2a9e99af595892c396a219c2bc11fb6c9 from: Omar Polo date: Mon Oct 04 09:04:33 2021 UTC rework the regression suite The tests are still there, the suite is equivalent to the old one, but this one is better structured. The biggest annoyance I had with the old one was that it wasn't straightforward to test only a specific set of tests. It's still impossible, but it's way easier to do it now. This extract all the tests to their own functions. It's overall better in all possible regards. commit - c28994868efd1da6259f805984cc93135bd74a3a commit + 176179b2a9e99af595892c396a219c2bc11fb6c9 blob - 89f482a86586681209238c951bc26cf38de4aab9 blob + e4a5ff4006151dfd6ad11756657c4811ac086b7c --- .gitignore +++ .gitignore @@ -30,3 +30,4 @@ regress/iri_test regress/puny-test regress/*.o regress/gg +regress/gmid.pid blob - 0efddad3c22f99056a4831ab0d54ec83a972bd7b blob + 5b2d29bc8b92dc961007b069dc0ceb317a5c6ecb --- regress/Makefile +++ 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 blob - /dev/null blob + afee6f8df58e37649357b07a231104c674ecddff (mode 644) --- /dev/null +++ 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 +# generates a configuration file reg.conf +gen_config() { + cat < 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 +# generates a configuration file with `gen_config', validates it and +# launches the daemon +setup_simple_test() { + gen_config "$1" "$2" + run +} + +# usage: get +# return the body of the request on stdout +get() { + $gg -T30 -b $ggflags "gemini://localhost:10965/$1" +} + +# usage: head +# return the meta response line on stdout +head() { + $gg -T30 -h $ggflags "gemini://localhost:10965/$1" +} + +# usage: raw +# return both header and body +raw() { + $gg -T30 $ggflags "gemini://localhost:10965/$1" +} + +# usage: fetch +# 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 +# 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 +} blob - 7566a1a63f5b003417f3d114c3c76271525a509a blob + f34ff7d201527b969798ae1b889cc2924fa212b9 --- regress/runtime +++ 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= +rm -f gmid.pid -port=10965 +. ./lib.sh +. ./tests.sh -config_common=" -ipv6 off -port $port -" - -# usage: config -# generates a configuration file reg.conf -config() { - cat < 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 -# return the body of the request on stdout -get() { - ./gg -T30 -b $ggflags "gemini://localhost:10965/$1" -} - -# usage: head -# return the meta response line on stdout -head() { - ./gg -T30 -h $ggflags "gemini://localhost:10965/$1" -} - -# usage: raw -# 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 -} - -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 - trap 'onexit' INT TERM EXIT -endl=`printf "\r\n"` -lf=`echo` +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 -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 < 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 +if [ "$failed" != "" ]; then + echo + echo "failed tests:$failed" + exit 1 +fi blob - /dev/null blob + c01013ee788ada6fd1c527f8d6981607520a8275 (mode 644) --- /dev/null +++ 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 < 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 +}