blob: ec31546430a7723d4992359f426410ce28dbed53 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#!/bin/sh

# Checks the post-receive hooks under custom/hooks. The cache hook runs from a
# copy pointed at a cache and a scan path in the trash directory, since the
# shipped one names the system's own, and the hooks run inside bare
# repositories the way git runs them after a push.

test_description='Check the shipped post-receive hooks'
CGIT_TEST_NO_CREATE_REPOS=YesPlease
. ./setup.sh

HOOK_DIRECTORY="$TEST_OUTPUT_DIRECTORY/../custom/hooks"

# A cache that cgit itself filled, for two scanned repositories and the
# index, so the hook reads the keys cgit really writes.
test_expect_success 'set up a cache of two repositories and the index' '
	test_create_repo pusher &&
	test_commit -C pusher cached &&
	mkdir scan slots &&
	git init -q --bare scan/a.git &&
	git init -q --bare scan/b.git &&
	git -C pusher push -q ../scan/a.git HEAD:refs/heads/main &&
	git -C pusher push -q ../scan/b.git HEAD:refs/heads/main &&
	{
		echo "cache-root=$PWD/slots" &&
		echo "cache-size=1000" &&
		echo "virtual-root=/" &&
		echo "scan-path=$PWD/scan"
	} >cachedrc &&
	for page in / /a.git/ /a.git/log/ /b.git/ /b.git/log/
	do
		CGIT_CONFIG="$PWD/cachedrc" PATH_INFO="$page" QUERY_STRING= cgit >/dev/null ||
		return 1
	done &&
	cgit_rc cachedrc "url=a.git/refs/" >/dev/null &&
	cgit_rc cachedrc "url=b.git/refs/" >/dev/null &&
	echo writer >slots/0123abcd.lock &&
	cp -R slots pristine &&
	sed -e "s|^cache_root=.*|cache_root='\''$PWD/slots'\''|" \
		-e "s|^scan_path=.*|scan_path='\''$PWD/scan'\''|" \
		"$HOOK_DIRECTORY/post-receive.cgit-cache" >cache-hook
'

# The request each slot answers, read off its head the way the hook reads it.
cached_requests() {
	for slot in slots/*
	do
		dd if="$slot" bs=4096 count=1 2>/dev/null | tr "\0" "\n" | sed -n 1p
	done
}

# The hooks are POSIX sh, so each runs under every such shell that is here.
shells=
for shell in sh dash ksh bash
do
	command -v $shell >/dev/null && shells="$shells $shell"
done

for shell in $shells
do
	test_expect_success "a push drops its own pages and the index under $shell" "
		rm -rf slots && cp -R pristine slots &&
		(cd scan/a.git && $shell ../../cache-hook) &&
		cached_requests >left &&
		grep '|/b.git/log/' left &&
		grep 'url=b.git/refs/' left &&
		! grep 'a.git' left &&
		! grep '1|/0|' left &&
		test_path_is_file slots/0123abcd.lock &&
		! ls slots | grep '^rc-'
	"
done

test_expect_success 'a repository named in cgitrc gives the hook its url' '
	rm -rf slots && cp -R pristine slots &&
	git -C scan/b.git config hooks.cgiturl b.git &&
	sed "s|^scan_path=.*|scan_path=/nonexistent|" cache-hook >named-hook &&
	(cd scan/b.git && sh ../../named-hook) &&
	cached_requests >left &&
	grep "|/a.git/log/" left &&
	! grep "b.git" left
'

test_expect_success 'with no url to go on the whole cache goes' '
	rm -rf slots && cp -R pristine slots &&
	(cd scan/a.git && sh ../../named-hook) &&
	test "$(ls slots)" = 0123abcd.lock
'

test_expect_success SANITY 'the cache hook shows a pusher no error' '
	rm -rf slots && cp -R pristine slots &&
	test_when_finished "chmod 755 slots" &&
	chmod 555 slots &&
	(cd scan/a.git && sh ../../cache-hook 2>../../err) &&
	cached_requests | grep "a.git" &&
	test_must_be_empty err
'

test_expect_success 'the age hook writes the newest branch date' '
	test_create_repo work &&
	test_commit -C work first &&
	git init -q --bare plain.git &&
	git -C work push -q ../plain.git HEAD:refs/heads/main &&
	(cd plain.git && sh "$HOOK_DIRECTORY/post-receive.cgit-age") &&
	git -C plain.git for-each-ref --format="%(committerdate:iso8601)" refs/heads/main >expect &&
	test_cmp expect plain.git/info/web/last-modified
'

for shell in $shells
do
	test_expect_success "the age hook writes the same date under $shell" "
		rm -f plain.git/info/web/last-modified &&
		(cd plain.git && $shell \"\$HOOK_DIRECTORY/post-receive.cgit-age\") &&
		test_cmp expect plain.git/info/web/last-modified
	"
done

for shell in $shells
do
	test_expect_success SANITY "the age hook shows a pusher no error under $shell" "
		echo kept >kept &&
		cp kept plain.git/info/web/last-modified &&
		test_when_finished 'chmod 755 plain.git/info/web' &&
		chmod 555 plain.git/info/web &&
		(cd plain.git && $shell \"\$HOOK_DIRECTORY/post-receive.cgit-age\" 2>../err) &&
		test_must_be_empty err &&
		test_cmp kept plain.git/info/web/last-modified
	"
done

test_expect_success SANITY 'the age hook shows no error when it cannot make its directory' '
	git init -q --bare closed.git &&
	git -C work push -q ../closed.git HEAD:refs/heads/main &&
	test_when_finished "chmod 755 closed.git/info" &&
	chmod 555 closed.git/info &&
	(cd closed.git && sh "$HOOK_DIRECTORY/post-receive.cgit-age" 2>../err) &&
	test_must_be_empty err &&
	test_path_is_missing closed.git/info/web
'

# git keeps a shared repository group writable whatever the pusher's umask,
# and the next member to push has to be able to replace the file.
test_expect_success SANITY 'the age hook keeps a shared directory group writable' '
	git init -q --bare --shared=group shared.git &&
	git -C work push -q ../shared.git HEAD:refs/heads/main &&
	(cd shared.git && umask 022 && sh "$HOOK_DIRECTORY/post-receive.cgit-age") &&
	ls -ld shared.git/info/web >mode &&
	grep "^drwxrw[xs]" mode
'

test_expect_success 'the commit-graph hook writes a graph with path filters' '
	git init -q --bare graph.git &&
	git -C work push -q ../graph.git HEAD:refs/heads/main &&
	(cd graph.git && sh "$HOOK_DIRECTORY/post-receive.commit-graph" 2>../graph-err) &&
	test_must_be_empty graph-err &&
	test_path_is_file graph.git/objects/info/commit-graphs/commit-graph-chain &&
	grep -q BDAT graph.git/objects/info/commit-graphs/*.graph &&
	git -C graph.git commit-graph verify
'

for shell in $shells
do
	test_expect_success "a later push moves the graph on under $shell" "
		cat graph.git/objects/info/commit-graphs/commit-graph-chain >chain-$shell &&
		test_commit -C work graph-$shell &&
		git -C work push -q ../graph.git HEAD:refs/heads/main &&
		(cd graph.git && $shell \"\$HOOK_DIRECTORY/post-receive.commit-graph\") &&
		! test_cmp chain-$shell graph.git/objects/info/commit-graphs/commit-graph-chain &&
		git -C graph.git commit-graph verify
	"
done

test_done