From ea618c5e257a6aabded76e63567ec0e7b99ac6c4 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Mon, 24 Aug 2026 16:21:18 -1000 Subject: Renumber the test scripts into themed ranges t000x the ground the suite stands on: git version, html validity, the cache t01xx page content, one script per page t02xx features that cut across pages: filters, submodule links, dates, limits t03xx defence, the security regressions and the $HOME promise t04xx the helper tools under tools/ --- tests/t0003-cache.sh | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100755 tests/t0003-cache.sh (limited to 'tests/t0003-cache.sh') diff --git a/tests/t0003-cache.sh b/tests/t0003-cache.sh new file mode 100755 index 0000000..ca85d97 --- /dev/null +++ b/tests/t0003-cache.sh @@ -0,0 +1,200 @@ +#!/bin/sh + +# Exercises the cache, which keeps a rendered page in a slot on disk and +# replays it for the next request that asks for the same thing. The first three +# tests set cache-size to nothing, to one slot and to the full table in turn, +# then count what the requests left behind. The rest cover the two ways a slot +# can come out wrong, a page longer than the output buffer and a key too long +# to be read back. + +test_description='Validate cache' +. ./setup.sh + +test_expect_success 'verify cache-size=0' ' + + rm -f cache/* && + sed -e "s/cache-size=1021$/cache-size=0/" cgitrc >cgitrc.tmp && + mv -f cgitrc.tmp cgitrc && + cgit_url "" && + cgit_url "foo" && + cgit_url "foo/refs" && + cgit_url "foo/tree" && + cgit_url "foo/log" && + cgit_url "foo/diff" && + cgit_url "foo/patch" && + cgit_url "bar" && + cgit_url "bar/refs" && + cgit_url "bar/tree" && + cgit_url "bar/log" && + cgit_url "bar/diff" && + cgit_url "bar/patch" && + ls cache >output && + test_line_count = 0 output +' + +test_expect_success 'verify cache-size=1' ' + + rm -f cache/* && + sed -e "s/cache-size=0$/cache-size=1/" cgitrc >cgitrc.tmp && + mv -f cgitrc.tmp cgitrc && + cgit_url "" && + cgit_url "foo" && + cgit_url "foo/refs" && + cgit_url "foo/tree" && + cgit_url "foo/log" && + cgit_url "foo/diff" && + cgit_url "foo/patch" && + cgit_url "bar" && + cgit_url "bar/refs" && + cgit_url "bar/tree" && + cgit_url "bar/log" && + cgit_url "bar/diff" && + cgit_url "bar/patch" && + ls cache >output && + test_line_count = 1 output +' + +test_expect_success 'verify cache-size=1021' ' + + rm -f cache/* && + sed -e "s/cache-size=1$/cache-size=1021/" cgitrc >cgitrc.tmp && + mv -f cgitrc.tmp cgitrc && + cgit_url "" && + cgit_url "foo" && + cgit_url "foo/refs" && + cgit_url "foo/tree" && + cgit_url "foo/log" && + cgit_url "foo/diff" && + cgit_url "foo/patch" && + cgit_url "bar" && + cgit_url "bar/refs" && + cgit_url "bar/tree" && + cgit_url "bar/log" && + cgit_url "bar/diff" && + cgit_url "bar/patch" && + ls cache >output && + test_line_count = 13 output && + cgit_url "foo/ls_cache" >output.full && + strip_headers output && + test_line_count = 13 output && + cgit_url "foo/ls_cache" >output.second && + test_cmp output.full output.second +' + +# Page output is buffered, so a slot only holds the whole page if the buffer is +# emptied before the size of what was generated is taken. The blob set up here +# is larger than one buffer, so a missing flush would leave the cached copy cut +# short. +test_expect_success 'set up a repo with a page larger than the output buffer' ' + mkrepo repos/bigpage 1 && + ( + cd repos/bigpage && + awk "BEGIN{for(i=0;i<20000;i++) print \"line \" i \" of the big file\"}" >big.txt && + git add big.txt && + git commit -m "add big.txt" + ) && + { + echo "virtual-root=/" && + echo "cache-root=$PWD/cache2" && + echo "cache-size=64" && + echo "enable-tree-linenumbers=1" && + echo "repo.url=bigpage" && + echo "repo.path=$PWD/repos/bigpage/.git" + } >bigrc && + rm -rf cache2 && mkdir cache2 +' + +bigpage_query() +{ + CGIT_CONFIG="$PWD/bigrc" QUERY_STRING="$1" cgit +} + +test_expect_success 'the first request fills the slot and the second replays it' ' + bigpage_query "url=bigpage/tree/big.txt" >big.first && + test $(wc -c big.second && + strip_headers big.first.body && + strip_headers big.second.body && + test_cmp big.first.body big.second.body +' + +test_expect_success 'the cached body matches one generated with the cache off' ' + sed -e "s/^cache-size=64$/cache-size=0/" bigrc >bignocache && + CGIT_CONFIG="$PWD/bignocache" QUERY_STRING="url=bigpage/tree/big.txt" cgit >big.nocache && + strip_headers big.nocache.body && + # The footer carries the time the page was generated, which the two runs + # cannot agree on. + sed -e "s/generated by .*//" big.nocache.body >big.nocache.timeless && + sed -e "s/generated by .*//" big.second.body >big.cached.timeless && + test_cmp big.nocache.timeless big.cached.timeless +' + +test_expect_success 'the page ends where it should, so nothing was dropped' ' + tail -c 200 big.second.body | grep "" +' + +# A slot stores its key ahead of the content and only the first few kilobytes of +# it are read back, so a key longer than that could never match. A request +# carrying one used to leave a slot behind on every visit that nothing could +# ever go on to use. +test_expect_success 'an over-long cache key leaves no slot behind' ' + rm -rf cache3 && mkdir cache3 && + sed -e "s|^cache-root=.*|cache-root=$PWD/cache3|" bigrc >bigkeyrc && + long=$(awk "BEGIN{s=\"\";for(i=0;i<6000;i++)s=s \"k\"; print s}") && + CGIT_CONFIG="$PWD/bigkeyrc" QUERY_STRING="url=bigpage/&q=$long" cgit >key.out 2>key.err && + grep "" key.out && + ls cache3 >key.slots && + test_line_count = 0 key.slots +' + +test_expect_success 'an ordinary key still fills a slot' ' + rm -rf cache3 && mkdir cache3 && + CGIT_CONFIG="$PWD/bigkeyrc" QUERY_STRING="url=bigpage/" cgit >/dev/null && + ls cache3 >key.slots && + test_line_count = 1 key.slots +' + +# An error page fired after rendering began abandons the fill with part of +# the page already written into the lock file. That fragment must be +# discarded along with the file, not replayed to the visitor behind the +# error page. A commit whose parent object is missing renders its whole +# info table before the diff machinery fails, which makes it the trigger. +test_expect_success 'set up a repo missing a parent object' ' + mkrepo repos/broken 2 && + parent=$(git -C repos/broken rev-parse HEAD^) && + tip=$(git -C repos/broken rev-parse HEAD) && + rm "repos/broken/.git/objects/$(echo "$parent" | cut -c1-2)/$(echo "$parent" | cut -c3-)" && + { + echo "virtual-root=/" && + echo "cache-root=$PWD/cache4" && + echo "cache-size=64" && + echo "repo.url=broken" && + echo "repo.path=$PWD/repos/broken/.git" + } >brokenrc && + rm -rf cache4 && mkdir cache4 +' + +test_expect_success 'an error after output began replays none of it' ' + CGIT_CONFIG="$PWD/brokenrc" QUERY_STRING="url=broken/commit/&id=$tip" \ + cgit >broken.out && + grep "Bad commit" broken.out && + test $(grep -c "^Status:" broken.out) = 1 && + ls cache4 >broken.slots && + test_line_count = 0 broken.slots +' + +# An error page reports a condition the repository may grow out of, and a +# request pinned to an object id would cache it under the never-expiring +# static ttl. Asking for a commit that does not exist yet must therefore +# leave nothing behind, or the real page could never appear once it does. +test_expect_success 'an error page leaves no slot behind' ' + rm -rf cache3 && mkdir cache3 && + CGIT_CONFIG="$PWD/bigkeyrc" \ + QUERY_STRING="url=bigpage/commit/&id=0123456789abcdef0123456789abcdef01234567" \ + cgit >error.out && + grep "Bad commit reference" error.out && + ls cache3 >error.slots && + test_line_count = 0 error.slots +' + +test_done -- cgit v2.8.0