summaryrefslogtreecommitdiff
path: root/docs/handbook/cgit/testing.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/handbook/cgit/testing.md')
-rw-r--r--docs/handbook/cgit/testing.md335
1 files changed, 335 insertions, 0 deletions
diff --git a/docs/handbook/cgit/testing.md b/docs/handbook/cgit/testing.md
new file mode 100644
index 0000000000..ee7b5979f9
--- /dev/null
+++ b/docs/handbook/cgit/testing.md
@@ -0,0 +1,335 @@
+# cgit — Testing
+
+## Overview
+
+cgit has a shell-based test suite in the `tests/` directory. Tests use
+Git's own test framework (`test-lib.sh`) and exercise cgit by invoking the
+CGI binary with simulated HTTP requests.
+
+Source location: `cgit/tests/`.
+
+## Test Framework
+
+The test harness is built on Git's `test-lib.sh`, sourced from the vendored
+Git tree at `git/t/test-lib.sh`. This provides:
+
+- TAP-compatible output
+- Test assertions (`test_expect_success`, `test_expect_failure`)
+- Temporary directory management (`trash` directories)
+- Color-coded pass/fail reporting
+
+### `setup.sh`
+
+All test scripts source `tests/setup.sh`, which provides:
+
+```bash
+# Core test helpers
+prepare_tests() # Create repos and config file
+run_test() # Execute a single test case
+cgit_query() # Invoke cgit with a query string
+cgit_url() # Invoke cgit with a virtual URL
+strip_headers() # Remove HTTP headers from CGI output
+```
+
+### Invoking cgit
+
+Tests invoke cgit as a CGI binary by setting environment variables:
+
+```bash
+cgit_query()
+{
+ CGIT_CONFIG="$PWD/cgitrc" QUERY_STRING="$1" cgit
+}
+
+cgit_url()
+{
+ CGIT_CONFIG="$PWD/cgitrc" QUERY_STRING="url=$1" cgit
+}
+```
+
+The `cgit` binary is on PATH (prepended by setup.sh). The response includes
+HTTP headers followed by HTML content. `strip_headers()` removes the
+headers for content-only assertions.
+
+## Test Repository Setup
+
+`setup_repos()` creates test repositories:
+
+```bash
+setup_repos()
+{
+ rm -rf cache
+ mkdir -p cache
+ mkrepo repos/foo 5 # 5 commits
+ mkrepo repos/bar 50 commit-graph # 50 commits with commit-graph
+ mkrepo repos/foo+bar 10 testplus # 10 commits + special chars
+ mkrepo "repos/with space" 2 # repo with spaces in name
+ mkrepo repos/filter 5 testplus # for filter tests
+}
+```
+
+### `mkrepo()`
+
+```bash
+mkrepo() {
+ name=$1
+ count=$2
+ test_create_repo "$name"
+ (
+ cd "$name"
+ n=1
+ while test $n -le $count; do
+ echo $n >file-$n
+ git add file-$n
+ git commit -m "commit $n"
+ n=$(expr $n + 1)
+ done
+ case "$3" in
+ testplus)
+ echo "hello" >a+b
+ git add a+b
+ git commit -m "add a+b"
+ git branch "1+2"
+ ;;
+ commit-graph)
+ git commit-graph write
+ ;;
+ esac
+ )
+}
+```
+
+### Test Configuration
+
+A `cgitrc` file is generated in the test directory with:
+
+```ini
+virtual-root=/
+cache-root=$PWD/cache
+cache-size=1021
+snapshots=tar.gz tar.bz tar.lz tar.xz tar.zst zip
+enable-log-filecount=1
+enable-log-linecount=1
+summary-log=5
+summary-branches=5
+summary-tags=5
+clone-url=git://example.org/$CGIT_REPO_URL.git
+enable-filter-overrides=1
+root-coc=$PWD/site-coc.txt
+root-cla=$PWD/site-cla.txt
+root-homepage=https://projecttick.org
+root-homepage-title=Project Tick
+root-link=GitHub|https://github.com/example
+root-link=GitLab|https://gitlab.com/example
+root-link=Codeberg|https://codeberg.org/example
+
+repo.url=foo
+repo.path=$PWD/repos/foo/.git
+
+repo.url=bar
+repo.path=$PWD/repos/bar/.git
+repo.desc=the bar repo
+
+repo.url=foo+bar
+repo.path=$PWD/repos/foo+bar/.git
+repo.desc=the foo+bar repo
+# ...
+```
+
+## Test Scripts
+
+### Test File Naming
+
+Tests follow the convention `tNNNN-description.sh`:
+
+| Test | Description |
+|------|-------------|
+| `t0001-validate-git-versions.sh` | Verify Git version compatibility |
+| `t0010-validate-html.sh` | Validate HTML output |
+| `t0020-validate-cache.sh` | Test cache system |
+| `t0101-index.sh` | Repository index page |
+| `t0102-summary.sh` | Repository summary page |
+| `t0103-log.sh` | Log view |
+| `t0104-tree.sh` | Tree view |
+| `t0105-commit.sh` | Commit view |
+| `t0106-diff.sh` | Diff view |
+| `t0107-snapshot.sh` | Snapshot downloads |
+| `t0108-patch.sh` | Patch view |
+| `t0109-gitconfig.sh` | Git config integration |
+| `t0110-rawdiff.sh` | Raw diff output |
+| `t0111-filter.sh` | Filter system |
+| `t0112-coc.sh` | Code of Conduct page |
+| `t0113-cla.sh` | CLA page |
+| `t0114-root-homepage.sh` | Root homepage links |
+
+### Number Ranges
+
+| Range | Category |
+|-------|----------|
+| `t0001-t0099` | Infrastructure/validation tests |
+| `t0100-t0199` | Feature tests |
+
+## Running Tests
+
+### All Tests
+
+```bash
+cd cgit/tests
+make
+```
+
+The Makefile discovers all `t*.sh` files and runs them:
+
+```makefile
+T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
+
+all: $(T)
+
+$(T):
+ @'$(SHELL_PATH_SQ)' $@ $(CGIT_TEST_OPTS)
+```
+
+### Individual Tests
+
+```bash
+# Run a single test
+./t0101-index.sh
+
+# With verbose output
+./t0101-index.sh -v
+
+# With Valgrind
+./t0101-index.sh --valgrind
+```
+
+### Test Options
+
+Options are passed via `CGIT_TEST_OPTS` or command-line arguments:
+
+| Option | Description |
+|--------|-------------|
+| `-v`, `--verbose` | Show test details |
+| `--valgrind` | Run cgit under Valgrind |
+| `--debug` | Show shell trace |
+
+### Valgrind Support
+
+`setup.sh` intercepts the `--valgrind` flag and configures Valgrind
+instrumentation via a wrapper script in `tests/valgrind/`:
+
+```bash
+if test -n "$cgit_valgrind"; then
+ GIT_VALGRIND="$TEST_DIRECTORY/valgrind"
+ CGIT_VALGRIND=$(cd ../valgrind && pwd)
+ PATH="$CGIT_VALGRIND/bin:$PATH"
+fi
+```
+
+## Test Patterns
+
+### HTML Content Assertion
+
+```bash
+run_test 'repo index contains foo' '
+ cgit_url "/" | strip_headers | grep -q "foo"
+'
+```
+
+### HTTP Header Assertion
+
+```bash
+run_test 'content type is text/html' '
+ cgit_url "/" | head -1 | grep -q "Content-Type: text/html"
+'
+```
+
+### Snapshot Download
+
+```bash
+run_test 'snapshot is valid tar.gz' '
+ cgit_url "/foo/snapshot/foo-master.tar.gz" | strip_headers | \
+ gunzip | tar tf - >/dev/null
+'
+```
+
+### Negative Assertion
+
+```bash
+run_test 'no 404 on valid repo' '
+ ! cgit_url "/foo" | grep -q "404"
+'
+```
+
+### Lua Filter Conditional
+
+```bash
+if [ $CGIT_HAS_LUA -eq 1 ]; then
+ run_test 'lua filter works' '
+ cgit_url "/filter-lua/about/" | strip_headers | grep -q "filtered"
+ '
+fi
+```
+
+## Test Filter Scripts
+
+The `tests/filters/` directory contains simple filter scripts for testing:
+
+### `dump.sh`
+
+A passthrough filter that copies stdin to stdout, used to verify filter
+invocation:
+
+```bash
+#!/bin/sh
+cat
+```
+
+### `dump.lua`
+
+Lua equivalent of the dump filter:
+
+```lua
+function filter_open(...)
+end
+
+function write(str)
+ html(str)
+end
+
+function filter_close()
+ return 0
+end
+```
+
+## Cleanup
+
+```bash
+cd cgit/tests
+make clean
+```
+
+Removes the `trash` directories created by tests.
+
+## Writing New Tests
+
+1. Create a new file `tNNNN-description.sh`
+2. Source `setup.sh` and call `prepare_tests`:
+
+```bash
+#!/bin/sh
+. ./setup.sh
+prepare_tests "my new feature"
+
+run_test 'description of test case' '
+ cgit_url "/foo/my-page/" | strip_headers | grep -q "expected"
+'
+```
+
+3. Make it executable: `chmod +x tNNNN-description.sh`
+4. Run: `./tNNNN-description.sh -v`
+
+## CI Integration
+
+Tests are run as part of the CI pipeline. The `ci/` directory contains
+Nix-based CI configuration that builds cgit and runs the test suite in a
+reproducible environment.