xref: /src/libexec/pkg-serve/tests/pkg_serve_test.sh (revision b42e852e89cb04cceb6e0226d6a08cab13fb6e90)
1#-
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2026 Baptiste Daroussin <bapt@FreeBSD.org>
5
6PKG_SERVE="${PKG_SERVE:-/usr/libexec/pkg-serve}"
7
8serve()
9{
10	printf "$1" | "${PKG_SERVE}" "$2"
11}
12
13check_output()
14{
15	local pattern="$1" ; shift
16	output=$(serve "$@")
17	case "$output" in
18	*${pattern}*)
19		return 0
20		;;
21	*)
22		echo "Expected pattern: ${pattern}"
23		echo "Got: ${output}"
24		return 1
25		;;
26	esac
27}
28
29atf_test_case greeting
30greeting_head()
31{
32	atf_set "descr" "Server sends greeting on connect"
33}
34greeting_body()
35{
36	mkdir repo
37	check_output "ok: pkg-serve " "quit\n" repo ||
38	    atf_fail "greeting not found"
39}
40
41atf_test_case unknown_command
42unknown_command_head()
43{
44	atf_set "descr" "Unknown commands get ko response"
45}
46unknown_command_body()
47{
48	mkdir repo
49	check_output "ko: unknown command 'plop'" "plop\nquit\n" repo ||
50	    atf_fail "expected ko for unknown command"
51}
52
53atf_test_case get_missing_file
54get_missing_file_head()
55{
56	atf_set "descr" "Requesting a missing file returns ko"
57}
58get_missing_file_body()
59{
60	mkdir repo
61	check_output "ko: file not found" "get nonexistent.pkg 0\nquit\n" repo ||
62	    atf_fail "expected file not found"
63}
64
65atf_test_case get_file
66get_file_head()
67{
68	atf_set "descr" "Requesting an existing file returns its content"
69}
70get_file_body()
71{
72	mkdir repo
73	echo "testcontent" > repo/test.pkg
74	output=$(serve "get test.pkg 0\nquit\n" repo)
75	echo "$output" | grep -q "ok: 12" ||
76	    atf_fail "expected ok: 12, got: ${output}"
77	echo "$output" | grep -q "testcontent" ||
78	    atf_fail "expected testcontent in output"
79}
80
81atf_test_case get_file_leading_slash
82get_file_leading_slash_head()
83{
84	atf_set "descr" "Leading slash in path is stripped"
85}
86get_file_leading_slash_body()
87{
88	mkdir repo
89	echo "testcontent" > repo/test.pkg
90	check_output "ok: 12" "get /test.pkg 0\nquit\n" repo ||
91	    atf_fail "leading slash not stripped"
92}
93
94atf_test_case get_file_uptodate
95get_file_uptodate_head()
96{
97	atf_set "descr" "File with old mtime returns ok: 0"
98}
99get_file_uptodate_body()
100{
101	mkdir repo
102	echo "testcontent" > repo/test.pkg
103	check_output "ok: 0" "get test.pkg 9999999999\nquit\n" repo ||
104	    atf_fail "expected ok: 0 for up-to-date file"
105}
106
107atf_test_case get_directory
108get_directory_head()
109{
110	atf_set "descr" "Requesting a directory returns ko"
111}
112get_directory_body()
113{
114	mkdir -p repo/subdir
115	check_output "ko: not a file" "get subdir 0\nquit\n" repo ||
116	    atf_fail "expected not a file"
117}
118
119atf_test_case get_missing_age
120get_missing_age_head()
121{
122	atf_set "descr" "get without age argument returns error"
123}
124get_missing_age_body()
125{
126	mkdir repo
127	check_output "ko: bad command get" "get test.pkg\nquit\n" repo ||
128	    atf_fail "expected bad command get"
129}
130
131atf_test_case get_bad_age
132get_bad_age_head()
133{
134	atf_set "descr" "get with non-numeric age returns error"
135}
136get_bad_age_body()
137{
138	mkdir repo
139	check_output "ko: bad number" "get test.pkg notanumber\nquit\n" repo ||
140	    atf_fail "expected bad number"
141}
142
143atf_test_case get_empty_arg
144get_empty_arg_head()
145{
146	atf_set "descr" "get with no arguments returns error"
147}
148get_empty_arg_body()
149{
150	mkdir repo
151	check_output "ko: bad command get" "get \nquit\n" repo ||
152	    atf_fail "expected bad command get"
153}
154
155atf_test_case path_traversal
156path_traversal_head()
157{
158	atf_set "descr" "Path traversal with .. is rejected"
159}
160path_traversal_body()
161{
162	mkdir repo
163	check_output "ko: file not found" \
164	    "get ../etc/passwd 0\nquit\n" repo ||
165	    atf_fail "path traversal not rejected"
166}
167
168atf_test_case get_subdir_file
169get_subdir_file_head()
170{
171	atf_set "descr" "Files in subdirectories are served"
172}
173get_subdir_file_body()
174{
175	mkdir -p repo/sub
176	echo "subcontent" > repo/sub/file.pkg
177	output=$(serve "get sub/file.pkg 0\nquit\n" repo)
178	echo "$output" | grep -q "ok: 11" ||
179	    atf_fail "expected ok: 11, got: ${output}"
180	echo "$output" | grep -q "subcontent" ||
181	    atf_fail "expected subcontent in output"
182}
183
184atf_test_case multiple_gets
185multiple_gets_head()
186{
187	atf_set "descr" "Multiple get commands in one session"
188}
189multiple_gets_body()
190{
191	mkdir repo
192	echo "aaa" > repo/a.pkg
193	echo "bbb" > repo/b.pkg
194	output=$(serve "get a.pkg 0\nget b.pkg 0\nquit\n" repo)
195	echo "$output" | grep -q "ok: 4" ||
196	    atf_fail "expected ok: 4 for a.pkg"
197	echo "$output" | grep -q "aaa" ||
198	    atf_fail "expected content of a.pkg"
199	echo "$output" | grep -q "bbb" ||
200	    atf_fail "expected content of b.pkg"
201}
202
203atf_test_case bad_basedir
204bad_basedir_head()
205{
206	atf_set "descr" "Non-existent basedir causes exit failure"
207}
208bad_basedir_body()
209{
210	atf_check -s not-exit:0 -e match:"open" \
211	    "${PKG_SERVE}" /nonexistent/path
212}
213
214atf_init_test_cases()
215{
216	atf_add_test_case greeting
217	atf_add_test_case unknown_command
218	atf_add_test_case get_missing_file
219	atf_add_test_case get_file
220	atf_add_test_case get_file_leading_slash
221	atf_add_test_case get_file_uptodate
222	atf_add_test_case get_directory
223	atf_add_test_case get_missing_age
224	atf_add_test_case get_bad_age
225	atf_add_test_case get_empty_arg
226	atf_add_test_case path_traversal
227	atf_add_test_case get_subdir_file
228	atf_add_test_case multiple_gets
229	atf_add_test_case bad_basedir
230}
231