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