Skip to content

Commit 09baac7

Browse files
committed
multi-arch-test-build: add generic package tests
Check if any of the package executables return the expected version when called with a generic list of flags, e.g. --version, -v, etc. Check if executable and library symlinks are valid. Check if executables are marked as such. Check for hardcoded paths. Check if binaries are stripped. Check if all shared linked libraries are installed. Check if libraries have sonames and if so, if they have a soname symlink. Signed-off-by: George Sapkin <george@sapk.in>
1 parent 78aabe1 commit 09baac7

1 file changed

Lines changed: 212 additions & 30 deletions

File tree

.github/scripts/test_entrypoint.sh

Lines changed: 212 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,191 @@ set -o nounset # undefined variables causes script to fail
77
mkdir -p /var/lock/
88
mkdir -p /var/log/
99

10-
if [ $PKG_MANAGER = "opkg" ]; then
10+
CI_HELPERS="${CI_HELPERS:-/scripts/ci_helpers.sh}"
11+
12+
source "$CI_HELPERS"
13+
14+
is_exec() {
15+
[ -x "$1" ] && echo "$1" | grep -qE '^(/bin/|/sbin/|/usr/bin/|/usr/sbin/|/usr/libexec/)'
16+
}
17+
18+
is_lib() {
19+
echo "$1" | grep -qE '^(/lib/|/usr/lib/)'
20+
}
21+
22+
check_hardcoded_paths() {
23+
local file="$1"
24+
25+
if strings "$file" | grep -E '/home/|/build_dir/'; then
26+
status_warn "Binary $file contains a hardcoded build path"
27+
return 1
28+
fi
29+
30+
status_pass "Binary $file does not contain any hardcoded build paths"
31+
return 0
32+
}
33+
34+
check_exec() {
35+
local file="$1"
36+
local has_failure=0
37+
38+
if [ -x "$file" ]; then
39+
status_pass "File $file is executable"
40+
else
41+
status_fail "File $file in executable path is not executable"
42+
has_failure=1
43+
fi
44+
45+
local found_version=0
46+
for flag in --version -version version -v -V --help -help -?; do
47+
if "$file" "$flag" 2>&1 | grep -F "$PKG_VERSION"; then
48+
status_pass "Found version $PKG_VERSION in $file"
49+
found_version=1
50+
break
51+
fi
52+
done
53+
54+
if [ "$found_version" = 0 ]; then
55+
status_fail "Failed to find version $PKG_VERSION in $file"
56+
has_failure=1
57+
fi
58+
59+
if [ "$has_failure" = 1 ]; then
60+
return 1
61+
fi
62+
63+
return 0
64+
}
65+
66+
check_linked_libs() {
67+
local file="$1"
68+
local missing_libs
69+
missing_libs=$(ldd "$file" 2>/dev/null | grep "not found" || true)
70+
if [ -n "$missing_libs" ]; then
71+
status_fail "File $file has missing libraries:"
72+
echo "$missing_libs"
73+
return 1
74+
fi
75+
76+
status_pass "All linked libraries for $file are present"
77+
return 0
78+
}
79+
80+
check_lib() {
81+
local file="$1"
82+
local has_failure=0
83+
local soname
84+
soname=$(readelf -d "$file" 2>/dev/null | grep 'SONAME' | sed -E 's/.*\[(.*)\].*/\1/')
85+
if [ -n "$soname" ]; then
86+
if [ "$(basename "$file")" = "$soname" ]; then
87+
status_warn "Library $file has the same name as its SONAME '$soname'. The library file should have a more specific version."
88+
else
89+
status_pass "Library $file has SONAME '$soname'"
90+
fi
91+
92+
# When a library has a SONAME, there should be a symlink with the SONAME
93+
# pointing to the library file. This is usually in the same directory.
94+
local lib_dir
95+
lib_dir=$(dirname "$file")
96+
if [ ! -L "$lib_dir/$soname" ]; then
97+
status_fail "Library $file has SONAME '$soname' but no corresponding symlink was found in $lib_dir"
98+
has_failure=1
99+
elif [ "$(readlink -f "$lib_dir/$soname")" != "$(readlink -f "$file")" ]; then
100+
status_fail "Symlink for SONAME '$soname' does not point to $file"
101+
has_failure=1
102+
else
103+
status_pass "SONAME link for $file is correct"
104+
fi
105+
else
106+
status_warn "Library $file doesn't have a SONAME"
107+
fi
108+
109+
if [ "$has_failure" = 1 ]; then
110+
return 1
111+
fi
112+
113+
return 0
114+
}
115+
116+
do_generic_tests() {
117+
local all_files
118+
if [ "$PKG_MANAGER" = 'opkg' ]; then
119+
all_files=$(opkg files "$PKG_NAME")
120+
elif [ "$PKG_MANAGER" = 'apk' ]; then
121+
all_files=$(apk info --contents "$PKG_NAME" | sed 's#^#/#')
122+
fi
123+
124+
local files
125+
files=$(echo "$all_files" | grep -E '^(/bin/|/sbin/|/usr/bin/|/usr/libexec/|/usr/sbin/|/lib/|/usr/lib/)')
126+
127+
local has_failure=0
128+
for file in $files; do
129+
if [ ! -e "$file" ]; then
130+
# opkg files can list directories
131+
continue
132+
fi
133+
134+
# Check if it is a symlink and if the target exists
135+
if [ -L "$file" ]; then
136+
if [ -e "$(readlink -f "$file")" ]; then
137+
status_pass "Symlink $file points to an existing file"
138+
else
139+
status_fail "Symlink $file points to a non-existent file"
140+
has_failure=1
141+
fi
142+
143+
# Skip symlinks
144+
continue
145+
fi
146+
147+
if is_exec "$file" && ! check_exec "$file"; then
148+
has_failure=1
149+
fi
150+
151+
# Skip non-ELF files
152+
if ! file "$file" | grep -q "ELF"; then
153+
continue
154+
fi
155+
156+
check_hardcoded_paths "$file"
157+
158+
if file "$file" | grep "stripped"; then
159+
status_warn "Binary $file is not stripped"
160+
else
161+
status_pass "Binary $file is stripped"
162+
fi
163+
164+
if ! check_linked_libs "$file"; then
165+
has_failure=1
166+
fi
167+
168+
if is_lib "$file" && ! check_lib "$file"; then
169+
has_failure=1
170+
fi
171+
done
172+
173+
if [ "$has_failure" = 1 ]; then
174+
err "Generic tests failed"
175+
return 1
176+
fi
177+
178+
success "Generic tests passed"
179+
return 0
180+
}
181+
182+
if [ "$PKG_MANAGER" = 'opkg' ]; then
11183
echo "src/gz packages_ci file:///ci" >> /etc/opkg/distfeeds.conf
12184
opkg update
13-
elif [ $PKG_MANAGER = "apk" ]; then
185+
opkg install binutils file
186+
187+
elif [ "$PKG_MANAGER" = 'apk' ]; then
14188
echo "/ci/packages.adb" >> /etc/apk/repositories.d/distfeeds.list
15189
apk update
190+
apk add binutils file
16191
fi
17192

18-
CI_HELPERS="${CI_HELPERS:-/scripts/ci_helpers.sh}"
19-
20193
for PKG in /ci/*.[ai]pk; do
21-
if [ $PKG_MANAGER = "opkg" ]; then
194+
if [ "$PKG_MANAGER" = 'opkg' ]; then
22195
tar -xzOf "$PKG" ./control.tar.gz | tar xzf - ./control
23196
# package name including variant
24197
PKG_NAME=$(sed -ne 's#^Package: \(.*\)$#\1#p' ./control)
@@ -28,7 +201,8 @@ for PKG in /ci/*.[ai]pk; do
28201
# package source containing test.sh script
29202
PKG_SOURCE=$(sed -ne 's#^Source: \(.*\)$#\1#p' ./control)
30203
PKG_SOURCE="${PKG_SOURCE#/feed/}"
31-
elif [ $PKG_MANAGER = "apk" ]; then
204+
205+
elif [ "$PKG_MANAGER" = 'apk' ]; then
32206
# package name including variant
33207
PKG_NAME=$(apk adbdump --format json "$PKG" | jsonfilter -e '@["info"]["name"]')
34208
# package version without release
@@ -40,52 +214,60 @@ for PKG in /ci/*.[ai]pk; do
40214
fi
41215

42216
echo
43-
echo "Testing package $PKG_NAME in version $PKG_VERSION from $PKG_SOURCE"
217+
info "Testing package version $PKG_VERSION from $PKG_SOURCE"
44218

45219
if ! [ -d "/ci/$PKG_SOURCE" ]; then
46-
echo "$PKG_SOURCE is not a directory"
47-
exit 1
220+
err_die "$PKG_SOURCE is not a directory"
48221
fi
49222

50223
PRE_TEST_SCRIPT="/ci/$PKG_SOURCE/pre-test.sh"
51224
TEST_SCRIPT="/ci/$PKG_SOURCE/test.sh"
52225

53-
if ! [ -f "$TEST_SCRIPT" ]; then
54-
echo "No test.sh script available"
55-
continue
56-
fi
57-
58226
export PKG_NAME PKG_VERSION CI_HELPERS
59227

60228
if [ -f "$PRE_TEST_SCRIPT" ]; then
61-
echo "Use package specific pre-test.sh"
229+
info "Use the package-specific pre-test.sh"
62230
if sh "$PRE_TEST_SCRIPT" "$PKG_NAME" "$PKG_VERSION"; then
63-
echo "Pre-test successful"
231+
success "Pre-test successful"
64232
else
65-
echo "Pre-test failed"
66-
exit 1
233+
err_die "Pre-test failed"
67234
fi
235+
68236
else
69-
echo "No pre-test.sh script available"
237+
info "No pre-test.sh script available"
70238
fi
71239

72-
if [ $PKG_MANAGER = "opkg" ]; then
240+
if [ "$PKG_MANAGER" = 'opkg' ]; then
73241
opkg install "$PKG"
74-
elif [ $PKG_MANAGER = "apk" ]; then
242+
elif [ "$PKG_MANAGER" = 'apk' ]; then
75243
apk add --allow-untrusted "$PKG"
76244
fi
77245

78-
echo "Use package specific test.sh"
79-
if sh "$TEST_SCRIPT" "$PKG_NAME" "$PKG_VERSION"; then
80-
echo "Test successful"
246+
SUCCESS=0
247+
if [ -f "$TEST_SCRIPT" ]; then
248+
info "Use the package-specific test.sh"
249+
if sh "$TEST_SCRIPT" "$PKG_NAME" "$PKG_VERSION"; then
250+
success "Test successful"
251+
SUCCESS=1
252+
else
253+
err "Test failed"
254+
fi
81255
else
82-
echo "Test failed"
83-
exit 1
256+
warn "Use generic tests"
257+
if do_generic_tests; then
258+
SUCCESS=1
259+
fi
84260
fi
85261

86-
if [ $PKG_MANAGER = "opkg" ]; then
87-
opkg remove "$PKG_NAME" --force-removal-of-dependent-packages --force-remove --autoremove || true
88-
elif [ $PKG_MANAGER = "apk" ]; then
89-
apk del -r "$PKG_NAME"
262+
if [ "$PKG_MANAGER" = 'opkg' ]; then
263+
opkg remove "$PKG_NAME" \
264+
--autoremove \
265+
--force-removal-of-dependent-packages \
266+
--force-remove \
267+
|| true
268+
elif [ "$PKG_MANAGER" = 'apk' ]; then
269+
apk del --rdepends "$PKG_NAME" || true
90270
fi
271+
272+
[ "$SUCCESS" = 1 ] || exit 1
91273
done

0 commit comments

Comments
 (0)