1#!/usr/bin/env bash
2#
3# Copyright (C) 2019-2021 Red Hat, Inc.
4# This file is part of elfutils.
5#
6# This file is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 3 of the License, or
9# (at your option) any later version.
10#
11# elfutils is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19. $srcdir/test-subr.sh  # includes set -e
20
21type curl 2>/dev/null || (echo "need curl"; exit 77)
22type rpm2cpio 2>/dev/null || (echo "need rpm2cpio"; exit 77)
23type cpio 2>/dev/null || (echo "need cpio"; exit 77)
24type bzcat 2>/dev/null || (echo "need bzcat"; exit 77)
25bsdtar --version | grep -q zstd && zstd=true || zstd=false
26echo "zstd=$zstd bsdtar=`bsdtar --version`"
27
28# for test case debugging, uncomment:
29#set -x
30VERBOSE=-vvv
31
32DB=${PWD}/.debuginfod_tmp.sqlite
33tempfiles $DB
34export DEBUGINFOD_CACHE_PATH=${PWD}/.client_cache
35
36PID1=0
37PID2=0
38PID3=0
39
40cleanup()
41{
42  if [ $PID1 -ne 0 ]; then kill $PID1; wait $PID1; fi
43  if [ $PID2 -ne 0 ]; then kill $PID2; wait $PID2; fi
44  if [ $PID3 -ne 0 ]; then kill $PID3; wait $PID3; fi
45
46  rm -rf F R D L Z ${PWD}/foobar ${PWD}/mocktree ${PWD}/.client_cache* ${PWD}/tmp*
47  exit_cleanup
48}
49
50# clean up trash if we were aborted early
51trap cleanup 0 1 2 3 5 9 15
52
53errfiles_list=
54err() {
55    for ports in $PORT1 $PORT2
56    do
57        echo $port metrics
58        curl -s http://127.0.0.1:$port/metrics
59        echo
60    done
61    for x in $errfiles_list
62    do
63        echo "$x"
64        cat $x
65        echo
66    done
67}
68trap err ERR
69
70errfiles() {
71    errfiles_list="$errfiles_list $*"
72}
73
74
75
76# find an unused port number
77while true; do
78    PORT1=`expr '(' $RANDOM % 1000 ')' + 9000`
79    ss -atn | fgrep ":$PORT1" || break
80done    
81
82# We want to run debuginfod in the background.  We also want to start
83# it with the same check/installcheck-sensitive LD_LIBRARY_PATH stuff
84# that the testrun alias sets.  But: we if we just use
85#    testrun .../debuginfod
86# it runs in a subshell, with different pid, so not helpful.
87#
88# So we gather the LD_LIBRARY_PATH with this cunning trick:
89ldpath=`testrun sh -c 'echo $LD_LIBRARY_PATH'`
90
91mkdir F R L D Z
92# not tempfiles F R L D Z - they are directories which we clean up manually
93ln -s ${abs_builddir}/dwfllines L/foo   # any program not used elsewhere in this test
94
95wait_ready()
96{
97  port=$1;
98  what=$2;
99  value=$3;
100  timeout=20;
101
102  echo "Wait $timeout seconds on $port for metric $what to change to $value"
103  while [ $timeout -gt 0 ]; do
104    mvalue="$(curl -s http://127.0.0.1:$port/metrics \
105              | grep "$what" | awk '{print $NF}')"
106    if [ -z "$mvalue" ]; then mvalue=0; fi
107      echo "metric $what: $mvalue"
108      if [ "$mvalue" -eq "$value" ]; then
109        break;
110    fi
111    sleep 0.5;
112    ((timeout--));
113  done;
114
115  if [ $timeout -eq 0 ]; then
116    echo "metric $what never changed to $value on port $port"
117    exit 1;
118  fi
119}
120
121# create a bogus .rpm file to evoke a metric-visible error
122# Use a cyclic symlink instead of chmod 000 to make sure even root
123# would see an error (running the testsuite under root is NOT encouraged).
124ln -s R/nothing.rpm R/nothing.rpm
125
126env LD_LIBRARY_PATH=$ldpath DEBUGINFOD_URLS= ${abs_builddir}/../debuginfod/debuginfod $VERBOSE -F -R -d $DB -p $PORT1 -t0 -g0 --fdcache-fds 1 --fdcache-mbs 2 --fdcache-mintmp 0 -Z .tar.xz -Z .tar.bz2=bzcat -v R F Z L > vlog$PORT1 2>&1 &
127PID1=$!
128tempfiles vlog$PORT1
129errfiles vlog$PORT1
130# Server must become ready
131wait_ready $PORT1 'ready' 1
132export DEBUGINFOD_URLS=http://127.0.0.1:$PORT1/   # or without trailing /
133
134# Be patient when run on a busy machine things might take a bit.
135export DEBUGINFOD_TIMEOUT=10
136
137# Check thread comm names
138ps -q $PID1 -e -L -o '%p %c %a' | grep groom
139ps -q $PID1 -e -L -o '%p %c %a' | grep scan
140ps -q $PID1 -e -L -o '%p %c %a' | grep traverse
141
142# We use -t0 and -g0 here to turn off time-based scanning & grooming.
143# For testing purposes, we just sic SIGUSR1 / SIGUSR2 at the process.
144
145########################################################################
146
147# Compile a simple program, strip its debuginfo and save the build-id.
148# Also move the debuginfo into another directory so that elfutils
149# cannot find it without debuginfod.
150echo "int main() { return 0; }" > ${PWD}/prog.c
151tempfiles prog.c
152# Create a subdirectory to confound source path names
153mkdir foobar
154gcc -Wl,--build-id -g -o prog ${PWD}/foobar///./../prog.c
155testrun ${abs_top_builddir}/src/strip -g -f prog.debug ${PWD}/prog
156BUILDID=`env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../src/readelf \
157          -a prog | grep 'Build ID' | cut -d ' ' -f 7`
158
159wait_ready $PORT1 'thread_work_total{role="traverse"}' 1
160mv prog F
161mv prog.debug F
162kill -USR1 $PID1
163# Wait till both files are in the index.
164wait_ready $PORT1 'thread_work_total{role="traverse"}' 2
165wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
166wait_ready $PORT1 'thread_busy{role="scan"}' 0
167
168########################################################################
169
170# Test whether elfutils, via the debuginfod client library dlopen hooks,
171# is able to fetch debuginfo from the local debuginfod.
172testrun ${abs_builddir}/debuginfod_build_id_find -e F/prog 1
173
174########################################################################
175
176# PR25628
177rm -rf $DEBUGINFOD_CACHE_PATH # clean it from previous tests
178
179# The query is designed to fail, while the 000-permission file should be created.
180testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo 01234567 || true
181if [ ! -f $DEBUGINFOD_CACHE_PATH/01234567/debuginfo ]; then
182  echo "could not find cache in $DEBUGINFOD_CACHE_PATH"
183  exit 1
184fi
185
186if [ -r $DEBUGINFOD_CACHE_PATH/01234567/debuginfo ]; then
187  echo "The cache $DEBUGINFOD_CACHE_PATH/01234567/debuginfo is readable"
188  exit 1
189fi
190
191bytecount_before=`curl -s http://127.0.0.1:$PORT1/metrics | grep 'http_responses_transfer_bytes_count{code="404"}'`
192testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo 01234567 || true
193bytecount_after=`curl -s http://127.0.0.1:$PORT1/metrics | grep 'http_responses_transfer_bytes_count{code="404"}'`
194if [ "$bytecount_before" != "$bytecount_after" ]; then
195  echo "http_responses_transfer_bytes_count{code="404"} has changed."
196  exit 1
197fi
198
199# set cache_miss_s to 0 and sleep 1 to make the mtime expire.
200echo 0 > $DEBUGINFOD_CACHE_PATH/cache_miss_s
201sleep 1
202bytecount_before=`curl -s http://127.0.0.1:$PORT1/metrics | grep 'http_responses_transfer_bytes_count{code="404"}'`
203testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo 01234567 || true
204bytecount_after=`curl -s http://127.0.0.1:$PORT1/metrics | grep 'http_responses_transfer_bytes_count{code="404"}'`
205if [ "$bytecount_before" == "$bytecount_after" ]; then
206  echo "http_responses_transfer_bytes_count{code="404"} should be incremented."
207  exit 1
208fi
209########################################################################
210
211# Test whether debuginfod-find is able to fetch those files.
212rm -rf $DEBUGINFOD_CACHE_PATH # clean it from previous tests
213filename=`testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID`
214cmp $filename F/prog.debug
215if [ -w $filename ]; then
216    echo "cache file writable, boo"
217    exit 1
218fi
219
220filename=`testrun ${abs_top_builddir}/debuginfod/debuginfod-find executable F/prog`
221cmp $filename F/prog
222
223# raw source filename
224filename=`testrun ${abs_top_builddir}/debuginfod/debuginfod-find source $BUILDID ${PWD}/foobar///./../prog.c`
225cmp $filename  ${PWD}/prog.c
226
227# and also the canonicalized one
228filename=`testrun ${abs_top_builddir}/debuginfod/debuginfod-find source $BUILDID ${PWD}/prog.c`
229cmp $filename  ${PWD}/prog.c
230
231
232########################################################################
233
234# Test whether the cache default locations are correct
235
236mkdir tmphome
237
238# $HOME/.cache should be created.
239testrun env HOME=$PWD/tmphome XDG_CACHE_HOME= DEBUGINFOD_CACHE_PATH= ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
240if [ ! -f $PWD/tmphome/.cache/debuginfod_client/$BUILDID/debuginfo ]; then
241  echo "could not find cache in $PWD/tmphome/.cache"
242  exit 1
243fi
244
245# $HOME/.cache should be found.
246testrun env HOME=$PWD/tmphome XDG_CACHE_HOME= DEBUGINFOD_CACHE_PATH= ${abs_top_builddir}/debuginfod/debuginfod-find executable $BUILDID
247if [ ! -f $PWD/tmphome/.cache/debuginfod_client/$BUILDID/executable ]; then
248  echo "could not find cache in $PWD/tmphome/.cache"
249  exit 1
250fi
251
252# $XDG_CACHE_HOME should take priority over $HOME.cache.
253testrun env HOME=$PWD/tmphome XDG_CACHE_HOME=$PWD/tmpxdg DEBUGINFOD_CACHE_PATH= ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
254if [ ! -f $PWD/tmpxdg/debuginfod_client/$BUILDID/debuginfo ]; then
255  echo "could not find cache in $PWD/tmpxdg/"
256  exit 1
257fi
258
259# A cache at the old default location ($HOME/.debuginfod_client_cache) should take
260# priority over $HOME/.cache, $XDG_CACHE_HOME.
261cp -r $DEBUGINFOD_CACHE_PATH tmphome/.debuginfod_client_cache
262
263# Add a file that doesn't exist in $HOME/.cache, $XDG_CACHE_HOME.
264mkdir tmphome/.debuginfod_client_cache/deadbeef
265echo ELF... > tmphome/.debuginfod_client_cache/deadbeef/debuginfo
266filename=`testrun env HOME=$PWD/tmphome XDG_CACHE_HOME=$PWD/tmpxdg DEBUGINFOD_CACHE_PATH= ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo deadbeef`
267cmp $filename tmphome/.debuginfod_client_cache/deadbeef/debuginfo
268
269# $DEBUGINFO_CACHE_PATH should take priority over all else.
270testrun env HOME=$PWD/tmphome XDG_CACHE_HOME=$PWD/tmpxdg DEBUGINFOD_CACHE_PATH=$PWD/tmpcache ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
271if [ ! -f $PWD/tmpcache/$BUILDID/debuginfo ]; then
272  echo "could not find cache in $PWD/tmpcache/"
273  exit 1
274fi
275
276########################################################################
277
278# Add artifacts to the search paths and test whether debuginfod finds them while already running.
279
280# Build another, non-stripped binary
281echo "int main() { return 0; }" > ${PWD}/prog2.c
282tempfiles prog2.c
283gcc -Wl,--build-id -g -o prog2 ${PWD}/prog2.c
284BUILDID2=`env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../src/readelf \
285          -a prog2 | grep 'Build ID' | cut -d ' ' -f 7`
286
287mv prog2 F
288kill -USR1 $PID1
289# Now there should be 3 files in the index
290wait_ready $PORT1 'thread_work_total{role="traverse"}' 3
291wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
292wait_ready $PORT1 'thread_busy{role="scan"}' 0
293
294# Rerun same tests for the prog2 binary
295filename=`testrun ${abs_top_builddir}/debuginfod/debuginfod-find -v debuginfo $BUILDID2 2>vlog`
296cmp $filename F/prog2
297cat vlog
298grep -q Progress vlog
299grep -q Downloaded.from vlog
300tempfiles vlog
301filename=`testrun env DEBUGINFOD_PROGRESS=1 ${abs_top_builddir}/debuginfod/debuginfod-find executable $BUILDID2 2>vlog2`
302cmp $filename F/prog2
303cat vlog2
304grep -q 'Downloading.*http' vlog2
305tempfiles vlog2
306filename=`testrun ${abs_top_builddir}/debuginfod/debuginfod-find source $BUILDID2 ${PWD}/prog2.c`
307cmp $filename ${PWD}/prog2.c
308
309cp -rvp ${abs_srcdir}/debuginfod-rpms R
310if [ "$zstd" = "false" ]; then  # nuke the zstd fedora 31 ones
311    rm -vrf R/debuginfod-rpms/fedora31
312fi
313
314cp -rvp ${abs_srcdir}/debuginfod-tars Z
315kill -USR1 $PID1
316# All rpms need to be in the index, except the dummy permission-000 one
317rpms=$(find R -name \*rpm | grep -v nothing | wc -l)
318wait_ready $PORT1 'scanned_files_total{source=".rpm archive"}' $rpms
319txz=$(find Z -name \*tar.xz | wc -l)
320wait_ready $PORT1 'scanned_files_total{source=".tar.xz archive"}' $txz
321tb2=$(find Z -name \*tar.bz2 | wc -l)
322wait_ready $PORT1 'scanned_files_total{source=".tar.bz2 archive"}' $tb2
323
324kill -USR1 $PID1  # two hits of SIGUSR1 may be needed to resolve .debug->dwz->srefs
325# Expect all source files found in the rpms (they are all called hello.c :)
326# We will need to extract all rpms (in their own directory) and could all
327# sources referenced in the .debug files.
328mkdir extracted
329cd extracted
330subdir=0;
331newrpms=$(find ../R -name \*\.rpm | grep -v nothing)
332for i in $newrpms; do
333    subdir=$[$subdir+1];
334    mkdir $subdir;
335    cd $subdir;
336    ls -lah ../$i
337    rpm2cpio ../$i | cpio -ivd;
338    cd ..;
339done
340sourcefiles=$(find -name \*\\.debug \
341	      | env LD_LIBRARY_PATH=$ldpath xargs \
342		${abs_top_builddir}/src/readelf --debug-dump=decodedline \
343	      | grep mtime: | wc --lines)
344cd ..
345rm -rf extracted
346
347wait_ready $PORT1 'found_sourcerefs_total{source=".rpm archive"}' $sourcefiles
348
349# Run a bank of queries against the debuginfod-rpms / debuginfod-debs test cases
350
351archive_test() {
352    __BUILDID=$1
353    __SOURCEPATH=$2
354    __SOURCESHA1=$3
355    
356    filename=`testrun ${abs_top_builddir}/debuginfod/debuginfod-find executable $__BUILDID`
357    buildid=`env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../src/readelf \
358             -a $filename | grep 'Build ID' | cut -d ' ' -f 7`
359    test $__BUILDID = $buildid
360    # check that timestamps are plausible - older than the near-present (tmpdir mtime)
361    test $filename -ot `pwd`
362
363    # run again to assure that fdcache is being enjoyed
364    filename=`testrun ${abs_top_builddir}/debuginfod/debuginfod-find executable $__BUILDID`
365    buildid=`env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../src/readelf \
366             -a $filename | grep 'Build ID' | cut -d ' ' -f 7`
367    test $__BUILDID = $buildid
368    test $filename -ot `pwd`
369
370    filename=`testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $__BUILDID`
371    buildid=`env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../src/readelf \
372             -a $filename | grep 'Build ID' | cut -d ' ' -f 7`
373    test $__BUILDID = $buildid
374    test $filename -ot `pwd`
375
376    if test "x$__SOURCEPATH" != "x"; then
377        filename=`testrun ${abs_top_builddir}/debuginfod/debuginfod-find source $__BUILDID $__SOURCEPATH`
378        hash=`cat $filename | sha1sum | awk '{print $1}'`
379        test $__SOURCESHA1 = $hash
380        test $filename -ot `pwd`
381    fi
382}
383
384
385# common source file sha1
386SHA=f4a1a8062be998ae93b8f1cd744a398c6de6dbb1
387# fedora31
388if [ $zstd = true ]; then
389    # fedora31 uses zstd compression on rpms, older rpm2cpio/libarchive can't handle it
390    # and we're not using the fancy -Z '.rpm=(rpm2cpio|zstdcat)<' workaround in this testsuite
391    archive_test 420e9e3308971f4b817cc5bf83928b41a6909d88 /usr/src/debug/hello3-1.0-2.x86_64/foobar////./../hello.c $SHA
392    archive_test 87c08d12c78174f1082b7c888b3238219b0eb265 /usr/src/debug/hello3-1.0-2.x86_64///foobar/./..//hello.c $SHA
393fi
394# fedora30
395archive_test c36708a78618d597dee15d0dc989f093ca5f9120 /usr/src/debug/hello2-1.0-2.x86_64/hello.c $SHA
396archive_test 41a236eb667c362a1c4196018cc4581e09722b1b /usr/src/debug/hello2-1.0-2.x86_64/hello.c $SHA
397# rhel7
398archive_test bc1febfd03ca05e030f0d205f7659db29f8a4b30 /usr/src/debug/hello-1.0/hello.c $SHA
399archive_test f0aa15b8aba4f3c28cac3c2a73801fefa644a9f2 /usr/src/debug/hello-1.0/hello.c $SHA
400# rhel6
401archive_test bbbf92ebee5228310e398609c23c2d7d53f6e2f9 /usr/src/debug/hello-1.0/hello.c $SHA
402archive_test d44d42cbd7d915bc938c81333a21e355a6022fb7 /usr/src/debug/hello-1.0/hello.c $SHA
403# arch
404archive_test cee13b2ea505a7f37bd20d271c6bc7e5f8d2dfcb /usr/src/debug/hello.c 7a1334e086b97e5f124003a6cfb3ed792d10cdf4
405
406RPM_BUILDID=d44d42cbd7d915bc938c81333a21e355a6022fb7 # in rhel6/ subdir, for a later test
407
408
409########################################################################
410
411# Drop some of the artifacts, run a groom cycle; confirm that
412# debuginfod has forgotten them, but remembers others
413
414rm -r R/debuginfod-rpms/rhel6/*
415kill -USR2 $PID1  # groom cycle
416# 1 groom cycle already took place at/soon-after startup, so -USR2 makes 2
417wait_ready $PORT1 'thread_work_total{role="groom"}' 2
418# Expect 4 rpms containing 2 buildids to be deleted by the groom
419wait_ready $PORT1 'groomed_total{decision="stale"}' 4
420
421rm -rf $DEBUGINFOD_CACHE_PATH # clean it from previous tests
422
423# this is one of the buildids from the groom-deleted rpms
424testrun ${abs_top_builddir}/debuginfod/debuginfod-find executable $RPM_BUILDID && false || true
425# but this one was not deleted so should be still around
426testrun ${abs_top_builddir}/debuginfod/debuginfod-find executable $BUILDID2
427
428########################################################################
429
430# PR26810: Now rename some files in the R directory, then rescan, so
431# there are two copies of the same buildid in the index, one for the
432# no-longer-existing file name, and one under the new name.
433
434# run a groom cycle to force server to drop its fdcache
435kill -USR2 $PID1  # groom cycle
436wait_ready $PORT1 'thread_work_total{role="groom"}' 3
437# move it around a couple of times to make it likely to hit a nonexistent entry during iteration
438mv R/debuginfod-rpms/rhel7 R/debuginfod-rpms/rhel7renamed
439kill -USR1 $PID1  # scan cycle
440wait_ready $PORT1 'thread_work_total{role="traverse"}' 6
441wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
442wait_ready $PORT1 'thread_busy{role="scan"}' 0
443mv R/debuginfod-rpms/rhel7renamed R/debuginfod-rpms/rhel7renamed2
444kill -USR1 $PID1  # scan cycle
445wait_ready $PORT1 'thread_work_total{role="traverse"}' 7
446wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
447wait_ready $PORT1 'thread_busy{role="scan"}' 0
448mv R/debuginfod-rpms/rhel7renamed2 R/debuginfod-rpms/rhel7renamed3
449kill -USR1 $PID1  # scan cycle
450wait_ready $PORT1 'thread_work_total{role="traverse"}' 8
451wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
452wait_ready $PORT1 'thread_busy{role="scan"}' 0
453
454# retest rhel7
455archive_test bc1febfd03ca05e030f0d205f7659db29f8a4b30 /usr/src/debug/hello-1.0/hello.c $SHA
456archive_test f0aa15b8aba4f3c28cac3c2a73801fefa644a9f2 /usr/src/debug/hello-1.0/hello.c $SHA
457
458egrep '(libc.error.*rhel7)|(bc1febfd03ca)|(f0aa15b8aba)' vlog$PORT1
459
460########################################################################
461
462# Federation mode
463
464# find another unused port
465while true; do
466    PORT2=`expr '(' $RANDOM % 1000 ')' + 9000`
467    ss -atn | fgrep ":$PORT2" || break
468done
469
470export DEBUGINFOD_CACHE_PATH=${PWD}/.client_cache2
471mkdir -p $DEBUGINFOD_CACHE_PATH
472# NB: inherits the DEBUGINFOD_URLS to the first server
473# NB: run in -L symlink-following mode for the L subdir
474env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../debuginfod/debuginfod $VERBOSE -F -U -d ${DB}_2 -p $PORT2 -L L D > vlog$PORT2 2>&1 &
475PID2=$!
476tempfiles vlog$PORT2
477errfiles vlog$PORT2
478tempfiles ${DB}_2
479wait_ready $PORT2 'ready' 1
480wait_ready $PORT2 'thread_work_total{role="traverse"}' 1
481wait_ready $PORT2 'thread_work_pending{role="scan"}' 0
482wait_ready $PORT2 'thread_busy{role="scan"}' 0
483
484wait_ready $PORT2 'thread_busy{role="http-buildid"}' 0
485wait_ready $PORT2 'thread_busy{role="http-metrics"}' 1
486
487# have clients contact the new server
488export DEBUGINFOD_URLS=http://127.0.0.1:$PORT2
489
490if type bsdtar 2>/dev/null; then
491    # copy in the deb files
492    cp -rvp ${abs_srcdir}/debuginfod-debs/*deb D
493    kill -USR1 $PID2
494    # All debs need to be in the index
495    debs=$(find D -name \*.deb | wc -l)
496    wait_ready $PORT2 'scanned_files_total{source=".deb archive"}' `expr $debs`
497    ddebs=$(find D -name \*.ddeb | wc -l)
498    wait_ready $PORT2 'scanned_files_total{source=".ddeb archive"}' `expr $ddebs`
499
500    # ubuntu
501    archive_test f17a29b5a25bd4960531d82aa6b07c8abe84fa66 "" ""
502fi
503
504rm -rf $DEBUGINFOD_CACHE_PATH
505testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
506
507# send a request to stress XFF and User-Agent federation relay;
508# we'll grep for the two patterns in vlog$PORT1
509curl -s -H 'User-Agent: TESTCURL' -H 'X-Forwarded-For: TESTXFF' $DEBUGINFOD_URLS/buildid/deaddeadbeef00000000/debuginfo -o /dev/null || true
510
511grep UA:TESTCURL vlog$PORT1
512grep XFF:TESTXFF vlog$PORT1
513
514
515# confirm that first server can't resolve symlinked info in L/ but second can
516BUILDID=`env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../src/readelf \
517         -a L/foo | grep 'Build ID' | cut -d ' ' -f 7`
518file L/foo
519file -L L/foo
520export DEBUGINFOD_URLS=http://127.0.0.1:$PORT1
521rm -rf $DEBUGINFOD_CACHE_PATH
522testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID && false || true
523rm -f $DEBUGINFOD_CACHE_PATH/$BUILDID/debuginfo # drop 000-perm negative-hit file
524export DEBUGINFOD_URLS=http://127.0.0.1:$PORT2
525testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
526
527# test again with scheme free url
528export DEBUGINFOD_URLS=127.0.0.1:$PORT1
529rm -rf $DEBUGINFOD_CACHE_PATH
530testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID && false || true
531rm -f $DEBUGINFOD_CACHE_PATH/$BUILDID/debuginfo # drop 000-perm negative-hit file
532export DEBUGINFOD_URLS=127.0.0.1:$PORT2
533testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
534
535# test parallel queries in client
536export DEBUGINFOD_CACHE_PATH=${PWD}/.client_cache3
537mkdir -p $DEBUGINFOD_CACHE_PATH
538export DEBUGINFOD_URLS="BAD http://127.0.0.1:$PORT1 127.0.0.1:$PORT1 http://127.0.0.1:$PORT2 DNE"
539
540testrun ${abs_builddir}/debuginfod_build_id_find -e F/prog2 1
541
542########################################################################
543
544# Fetch some metrics
545curl -s http://127.0.0.1:$PORT1/badapi
546curl -s http://127.0.0.1:$PORT1/metrics
547curl -s http://127.0.0.1:$PORT2/metrics
548curl -s http://127.0.0.1:$PORT1/metrics | grep -q 'http_responses_total.*result.*error'
549curl -s http://127.0.0.1:$PORT1/metrics | grep -q 'http_responses_total.*result.*fdcache'
550curl -s http://127.0.0.1:$PORT2/metrics | grep -q 'http_responses_total.*result.*upstream'
551curl -s http://127.0.0.1:$PORT1/metrics | grep 'http_responses_duration_milliseconds_count'
552curl -s http://127.0.0.1:$PORT1/metrics | grep 'http_responses_duration_milliseconds_sum'
553curl -s http://127.0.0.1:$PORT1/metrics | grep 'http_responses_transfer_bytes_count'
554curl -s http://127.0.0.1:$PORT1/metrics | grep 'http_responses_transfer_bytes_sum'
555curl -s http://127.0.0.1:$PORT1/metrics | grep 'fdcache_'
556curl -s http://127.0.0.1:$PORT1/metrics | grep 'error_count'
557curl -s http://127.0.0.1:$PORT1/metrics | grep 'traversed_total'
558curl -s http://127.0.0.1:$PORT1/metrics | grep 'scanned_bytes_total'
559
560# And generate a few errors into the second debuginfod's logs, for analysis just below
561curl -s http://127.0.0.1:$PORT2/badapi > /dev/null || true
562curl -s http://127.0.0.1:$PORT2/buildid/deadbeef/debuginfo > /dev/null || true  
563# NB: this error is used to seed the 404 failure for the survive-404 tests
564
565# Confirm bad artifact types are rejected without leaving trace
566curl -s http://127.0.0.1:$PORT2/buildid/deadbeef/badtype > /dev/null || true
567(curl -s http://127.0.0.1:$PORT2/metrics | grep 'badtype') && false
568
569# Confirm that reused curl connections survive 404 errors.
570# The rm's force an uncached fetch
571rm -f $DEBUGINFOD_CACHE_PATH/$BUILDID/debuginfo .client_cache*/$BUILDID/debuginfo
572testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
573rm -f $DEBUGINFOD_CACHE_PATH/$BUILDID/debuginfo .client_cache*/$BUILDID/debuginfo
574testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
575testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
576testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
577rm -f $DEBUGINFOD_CACHE_PATH/$BUILDID/debuginfo .client_cache*/$BUILDID/debuginfo
578testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID
579
580# Confirm that some debuginfod client pools are being used
581curl -s http://127.0.0.1:$PORT2/metrics | grep 'dc_pool_op.*reuse'
582
583########################################################################
584# Corrupt the sqlite database and get debuginfod to trip across its errors
585curl -s http://127.0.0.1:$PORT1/metrics | grep 'sqlite3.*reset'
586ls -al $DB
587dd if=/dev/zero of=$DB bs=1 count=1
588ls -al $DB
589# trigger some random activity that's Sure to get sqlite3 upset
590kill -USR1 $PID1
591wait_ready $PORT1 'thread_work_total{role="traverse"}' 9
592wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
593wait_ready $PORT1 'thread_busy{role="scan"}' 0
594kill -USR2 $PID1
595wait_ready $PORT1 'thread_work_total{role="groom"}' 4
596curl -s http://127.0.0.1:$PORT1/buildid/beefbeefbeefd00dd00d/debuginfo > /dev/null || true
597curl -s http://127.0.0.1:$PORT1/metrics | grep 'error_count.*sqlite'
598
599########################################################################
600
601# Run the tests again without the servers running. The target file should
602# be found in the cache.
603
604kill -INT $PID1 $PID2
605wait $PID1 $PID2
606PID1=0
607PID2=0
608tempfiles .debuginfod_*
609
610testrun ${abs_builddir}/debuginfod_build_id_find -e F/prog2 1
611
612# check out the debuginfod logs for the new style status lines
613# cat vlog$PORT2
614grep -q 'UA:.*XFF:.*GET /buildid/.* 200 ' vlog$PORT2
615grep -q 'UA:.*XFF:.*GET /metrics 200 ' vlog$PORT2
616grep -q 'UA:.*XFF:.*GET /badapi 503 ' vlog$PORT2
617grep -q 'UA:.*XFF:.*GET /buildid/deadbeef.* 404 ' vlog$PORT2
618
619########################################################################
620
621# Add some files to the cache that do not fit its naming format.
622# They should survive cache cleaning.
623mkdir $DEBUGINFOD_CACHE_PATH/malformed
624touch $DEBUGINFOD_CACHE_PATH/malformed0
625touch $DEBUGINFOD_CACHE_PATH/malformed/malformed1
626
627# A valid format for an empty buildid subdirectory
628mkdir $DEBUGINFOD_CACHE_PATH/00000000
629touch -d '1970-01-01' $DEBUGINFOD_CACHE_PATH/00000000 # old enough to guarantee nukage
630
631# Trigger a cache clean and run the tests again. The clients should be unable to
632# find the target.
633echo 0 > $DEBUGINFOD_CACHE_PATH/cache_clean_interval_s
634echo 0 > $DEBUGINFOD_CACHE_PATH/max_unused_age_s
635
636testrun ${abs_builddir}/debuginfod_build_id_find -e F/prog 1
637
638testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo $BUILDID2 && false || true
639
640if [ ! -f $DEBUGINFOD_CACHE_PATH/malformed0 ] \
641    || [ ! -f $DEBUGINFOD_CACHE_PATH/malformed/malformed1 ]; then
642  echo "unrelated files did not survive cache cleaning"
643  exit 1
644fi
645
646if [ -d $DEBUGINFOD_CACHE_PATH/00000000 ]; then
647    echo "failed to rmdir old cache dir"
648    exit 1
649fi
650
651# Test debuginfod without a path list; reuse $PORT1
652env LD_LIBRARY_PATH=$ldpath ${abs_builddir}/../debuginfod/debuginfod $VERBOSE -F -U -d :memory: -p $PORT1 -L -F &
653PID3=$!
654wait_ready $PORT1 'thread_work_total{role="traverse"}' 1
655wait_ready $PORT1 'thread_work_pending{role="scan"}' 0
656wait_ready $PORT1 'thread_busy{role="scan"}' 0
657kill -int $PID3
658wait $PID3
659PID3=0
660
661########################################################################
662# Test fetching a file using file:// . No debuginfod server needs to be run for
663# this test.
664local_dir=${PWD}/mocktree/buildid/aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd/source/my/path
665mkdir -p ${local_dir}
666echo "int main() { return 0; }" > ${local_dir}/main.c
667
668# first test that is doesn't work, when no DEBUGINFOD_URLS is set
669DEBUGINFOD_URLS=""
670testrun ${abs_top_builddir}/debuginfod/debuginfod-find source aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd /my/path/main.c && false || true
671
672# Now test is with proper DEBUGINFOD_URLS
673DEBUGINFOD_URLS="file://${PWD}/mocktree/"
674filename=`testrun ${abs_top_builddir}/debuginfod/debuginfod-find source aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd /my/path/main.c`
675cmp $filename ${local_dir}/main.c
676
677exit 0
678