From e1a69e71efc0679815f722480169f16bf02622ab Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Mon, 12 May 2014 21:25:43 +0200 Subject: (try to) fix travis-ci build failures dpkg on Ubuntu 12.04 does not seem to support parsing arch-specific dependencies, so we try to detect if we face such a dpkg in the test. In the other test the order depends on libdb, which changes per arch, so we just run it through our sorting binary and be happy (hopefully). Git-Dch: Ignore --- test/integration/framework | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'test/integration/framework') diff --git a/test/integration/framework b/test/integration/framework index eda3cebad..4f0a69994 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -36,7 +36,7 @@ msgndebug() { echo -n "${CDEBUG}D: $1${CNORMAL}"; } msgtest() { while [ -n "$1" ]; do echo -n "${CINFO}$1${CCMD} " - echo -n "$(echo "$2" | sed -e 's/^aptc/apt-c/' -e 's/^aptg/apt-g/' -e 's/^aptf/apt-f/')${CINFO} " + echo -n "$(echo "$2" | sed -e 's#^apt\([cgfs]\)#apt-\1#')${CINFO} " shift if [ -n "$1" ]; then shift; else break; fi done @@ -114,6 +114,7 @@ aptget() { runapt apt-get "$@"; } aptftparchive() { runapt apt-ftparchive "$@"; } aptkey() { runapt apt-key "$@"; } aptmark() { runapt apt-mark "$@"; } +aptsortpkgs() { runapt apt-sortpkgs "$@"; } apt() { runapt apt "$@"; } apthelper() { runapt "${APTHELPERBINDIR}/apt-helper" "$@"; } aptwebserver() { runapt "${APTWEBSERVERBINDIR}/aptwebserver" "$@"; } -- cgit v1.2.3-70-g09d2 From 1f6cf9e79742ea8e328ef2225b2f5217a9440216 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 30 May 2014 18:01:47 +0200 Subject: support parsing EDSP requests Architecture{,s} stanza Adds also a small testcase for EDSP Git-Dch: Ignore --- apt-pkg/edsp.cc | 7 +++ test/integration/framework | 6 ++ .../test-external-dependency-solver-protocol | 65 ++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100755 test/integration/test-external-dependency-solver-protocol (limited to 'test/integration/framework') diff --git a/apt-pkg/edsp.cc b/apt-pkg/edsp.cc index 52556c1ed..6d1b68c23 100644 --- a/apt-pkg/edsp.cc +++ b/apt-pkg/edsp.cc @@ -438,6 +438,13 @@ bool EDSP::ReadRequest(int const input, std::list &install, distUpgrade = EDSP::StringToBool(line.c_str() + 14, false); else if (line.compare(0, 11, "Autoremove:") == 0) autoRemove = EDSP::StringToBool(line.c_str() + 12, false); + else if (line.compare(0, 13, "Architecture:") == 0) + _config->Set("APT::Architecture", line.c_str() + 14); + else if (line.compare(0, 14, "Architectures:") == 0) + { + std::string const archs = line.c_str() + 15; + _config->Set("APT::Architectures", SubstVar(archs, " ", ",")); + } else _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str()); diff --git a/test/integration/framework b/test/integration/framework index 4f0a69994..7959699fd 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -194,6 +194,12 @@ setupenvironment() { touch var/lib/dpkg/available mkdir -p usr/lib/apt ln -s ${METHODSDIR} usr/lib/apt/methods + if [ "$BUILDDIRECTORY" = "$LIBRARYPATH" ]; then + mkdir -p usr/lib/apt/solvers + ln -s "${BUILDDIRECTORY}/apt-dump-solver" usr/lib/apt/solvers/dump + ln -s "${BUILDDIRECTORY}/apt-internal-solver" usr/lib/apt/solvers/apt + echo "Dir::Bin::Solvers \"${TMPWORKINGDIRECTORY}/rootdir/usr/lib/apt/solvers\";" > etc/apt/apt.conf.d/externalsolver.conf + fi # use the autoremove from the BUILDDIRECTORY if its there, otherwise # system if [ -e ${BUILDDIRECTORY}/../../debian/apt.conf.autoremove ]; then diff --git a/test/integration/test-external-dependency-solver-protocol b/test/integration/test-external-dependency-solver-protocol new file mode 100755 index 000000000..129565993 --- /dev/null +++ b/test/integration/test-external-dependency-solver-protocol @@ -0,0 +1,65 @@ +#!/bin/sh +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework +setupenvironment +configarchitecture 'amd64' 'i386' + +insertinstalledpackage 'cool' 'all' '1' +insertinstalledpackage 'stuff' 'all' '1' + +insertpackage 'unstable' 'cool' 'all' '2' 'Multi-Arch: foreign' +insertpackage 'unstable' 'stuff' 'all' '2' 'Multi-Arch: foreign' +insertpackage 'unstable' 'coolstuff' 'i386,amd64' '2' 'Depends: cool, stuff' +insertpackage 'unstable' 'awesome' 'all' '2' 'Multi-Arch: foreign' +insertpackage 'unstable' 'awesomecoolstuff' 'i386' '2' 'Depends: coolstuff, awesome' + +insertpackage 'experimental' 'cool' 'all' '3' 'Multi-Arch: foreign' +insertpackage 'experimental' 'stuff' 'all' '3' 'Multi-Arch: foreign' +insertpackage 'experimental' 'coolstuff' 'i386,amd64' '3' 'Depends: cool, stuff' + +setupaptarchive + +rm -f /tmp/dump.edsp +testequal 'Reading package lists... +Building dependency tree... +Execute external solver... +The solver encountered an error of type: ERR_JUST_DUMPING +The following information might help you to understand what is wrong: +I am too dumb, i can just dump! +Please use one of my friends instead! + +E: External solver failed with: I am too dumb, i can just dump!' aptget install --solver dump coolstuff -s +testsuccess test -s /tmp/dump.edsp +rm -f /tmp/dump.edsp + +#FIXME: this should be unstable, but we don't support pinning yet +testequal 'Reading package lists... +Building dependency tree... +Execute external solver... +The following NEW packages will be installed: + coolstuff +0 upgraded, 1 newly installed, 0 to remove and 2 not upgraded. +Inst coolstuff (3 experimental [amd64]) +Conf coolstuff (3 experimental [amd64])' aptget install --solver apt coolstuff -s + +testsuccess aptget install awesomecoolstuff:i386 -s +testsuccess aptget install --solver apt awesomecoolstuff:i386 -s + +rm -f /tmp/dump.edsp +testfailure aptget install --solver dump awesomecoolstuff:i386 -s +testsuccess test -s /tmp/dump.edsp + +configarchitecture 'armel' +msgtest 'Test direct calling is okay for' 'apt-internal-solver' +cat /tmp/dump.edsp | runapt apt-internal-solver > solver.result 2>&1 || true +if [ "$(tail -n2 solver.result | head -n1 )" = "Message: Done" ]; then + msgpass +else + cat solver.result + msgfail +fi +rm -f /tmp/dump.edsp + +testfailure aptget install --solver apt awesomecoolstuff:i386 -s -- cgit v1.2.3-70-g09d2 From 686b484b407fdbef47d9f2064284a567b72417fe Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 11 Jun 2014 14:50:48 +0200 Subject: fix autopkgtest tests --- debian/tests/control | 2 +- debian/tests/run-tests | 1 + test/integration/framework | 2 ++ test/integration/test-external-dependency-solver-protocol | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) (limited to 'test/integration/framework') diff --git a/debian/tests/control b/debian/tests/control index 209f16bfd..72e9deef7 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -1,3 +1,3 @@ Tests: run-tests Restrictions: allow-stderr -Depends: @, build-essential, fakeroot, wget, dpkg-dev, debhelper, libdb-dev, gettext, libcurl4-gnutls-dev, zlib1g-dev, libbz2-dev, xsltproc, docbook-xsl, docbook-xml, po4a, autotools-dev, autoconf, automake, doxygen, debiandoc-sgml, stunnel4, libdb-dev +Depends: @, build-essential, fakeroot, wget, dpkg-dev, debhelper, libdb-dev, gettext, libcurl4-gnutls-dev, zlib1g-dev, libbz2-dev, xsltproc, docbook-xsl, docbook-xml, po4a, autotools-dev, autoconf, automake, doxygen, debiandoc-sgml, stunnel4, libdb-dev, db-util diff --git a/debian/tests/run-tests b/debian/tests/run-tests index e6bc5e0d1..ebea3b200 100644 --- a/debian/tests/run-tests +++ b/debian/tests/run-tests @@ -12,6 +12,7 @@ make -C test/interactive-helper/ APT_INTEGRATION_TESTS_WEBSERVER_BIN_DIR=$(pwd)/build/bin \ APT_INTEGRATION_TESTS_METHODS_DIR=/usr/lib/apt/methods \ APT_INTEGRATION_TESTS_LIBEXEC_DIR=/usr/lib/apt/ \ +APT_INTEGRATION_TESTS_INTERNAL_SOLVER_DIR=/usr/lib/apt/solvers \ APT_INTEGRATION_TESTS_BUILD_DIR=/usr/bin \ APT_INTEGRATION_TESTS_LIBRARY_PATH=/dev/null/does/not/exist \ ./test/integration/run-tests diff --git a/test/integration/framework b/test/integration/framework index 7959699fd..6c9e8bd57 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -120,6 +120,7 @@ apthelper() { runapt "${APTHELPERBINDIR}/apt-helper" "$@"; } aptwebserver() { runapt "${APTWEBSERVERBINDIR}/aptwebserver" "$@"; } aptitude() { runapt aptitude "$@"; } aptextracttemplates() { runapt apt-extracttemplates "$@"; } +aptinternalsolver() { runapt "${APTINTERNALSOLVERBINDIR}/apt-internal-solver" "$@"; } dpkg() { command dpkg --root=${TMPWORKINGDIRECTORY}/rootdir --force-not-root --force-bad-path --log=${TMPWORKINGDIRECTORY}/rootdir/var/log/dpkg.log "$@" @@ -181,6 +182,7 @@ setupenvironment() { METHODSDIR=${APT_INTEGRATION_TESTS_METHODS_DIR:-"${BUILDDIRECTORY}/methods"} APTHELPERBINDIR=${APT_INTEGRATION_TESTS_LIBEXEC_DIR:-"${BUILDDIRECTORY}"} APTWEBSERVERBINDIR=${APT_INTEGRATION_TESTS_WEBSERVER_BIN_DIR:-"${BUILDDIRECTORY}"} + APTINTERNALSOLVERBINDIR=${APT_INTEGRATION_TESTS_INTERNAL_SOLVER_DIR:-"${BUILDDIRECTORY}"} test -x "${BUILDDIRECTORY}/apt-get" || msgdie "You need to build tree first" # ----- diff --git a/test/integration/test-external-dependency-solver-protocol b/test/integration/test-external-dependency-solver-protocol index 129565993..09230d383 100755 --- a/test/integration/test-external-dependency-solver-protocol +++ b/test/integration/test-external-dependency-solver-protocol @@ -53,7 +53,7 @@ testsuccess test -s /tmp/dump.edsp configarchitecture 'armel' msgtest 'Test direct calling is okay for' 'apt-internal-solver' -cat /tmp/dump.edsp | runapt apt-internal-solver > solver.result 2>&1 || true +cat /tmp/dump.edsp | aptinternalsolver > solver.result 2>&1 || true if [ "$(tail -n2 solver.result | head -n1 )" = "Message: Done" ]; then msgpass else -- cgit v1.2.3-70-g09d2 From 3082603f0ef76876810cb8c6d02d03ba67ec8c6b Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 11 Jun 2014 18:17:45 +0200 Subject: fix test-apt-ftparchive-cachedb-lp1274466 and apt-internal-solver tests --- debian/tests/run-tests | 2 +- test/integration/framework | 4 ++-- test/integration/test-apt-ftparchive-cachedb-lp1274466 | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'test/integration/framework') diff --git a/debian/tests/run-tests b/debian/tests/run-tests index ebea3b200..308031e9d 100644 --- a/debian/tests/run-tests +++ b/debian/tests/run-tests @@ -12,7 +12,7 @@ make -C test/interactive-helper/ APT_INTEGRATION_TESTS_WEBSERVER_BIN_DIR=$(pwd)/build/bin \ APT_INTEGRATION_TESTS_METHODS_DIR=/usr/lib/apt/methods \ APT_INTEGRATION_TESTS_LIBEXEC_DIR=/usr/lib/apt/ \ -APT_INTEGRATION_TESTS_INTERNAL_SOLVER_DIR=/usr/lib/apt/solvers \ +APT_INTEGRATION_TESTS_INTERNAL_SOLVER=/usr/lib/apt/solvers/apt \ APT_INTEGRATION_TESTS_BUILD_DIR=/usr/bin \ APT_INTEGRATION_TESTS_LIBRARY_PATH=/dev/null/does/not/exist \ ./test/integration/run-tests diff --git a/test/integration/framework b/test/integration/framework index 6c9e8bd57..a687dcb35 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -120,7 +120,7 @@ apthelper() { runapt "${APTHELPERBINDIR}/apt-helper" "$@"; } aptwebserver() { runapt "${APTWEBSERVERBINDIR}/aptwebserver" "$@"; } aptitude() { runapt aptitude "$@"; } aptextracttemplates() { runapt apt-extracttemplates "$@"; } -aptinternalsolver() { runapt "${APTINTERNALSOLVERBINDIR}/apt-internal-solver" "$@"; } +aptinternalsolver() { runapt "${APTINTERNALSOLVER}" "$@"; } dpkg() { command dpkg --root=${TMPWORKINGDIRECTORY}/rootdir --force-not-root --force-bad-path --log=${TMPWORKINGDIRECTORY}/rootdir/var/log/dpkg.log "$@" @@ -182,7 +182,7 @@ setupenvironment() { METHODSDIR=${APT_INTEGRATION_TESTS_METHODS_DIR:-"${BUILDDIRECTORY}/methods"} APTHELPERBINDIR=${APT_INTEGRATION_TESTS_LIBEXEC_DIR:-"${BUILDDIRECTORY}"} APTWEBSERVERBINDIR=${APT_INTEGRATION_TESTS_WEBSERVER_BIN_DIR:-"${BUILDDIRECTORY}"} - APTINTERNALSOLVERBINDIR=${APT_INTEGRATION_TESTS_INTERNAL_SOLVER_DIR:-"${BUILDDIRECTORY}"} + APTINTERNALSOLVER=${APT_INTEGRATION_TESTS_INTERNAL_SOLVER:-"${BUILDDIRECTORY}/apt-internal-solver"} test -x "${BUILDDIRECTORY}/apt-get" || msgdie "You need to build tree first" # ----- diff --git a/test/integration/test-apt-ftparchive-cachedb-lp1274466 b/test/integration/test-apt-ftparchive-cachedb-lp1274466 index 2a28d6ef0..579ae33a6 100755 --- a/test/integration/test-apt-ftparchive-cachedb-lp1274466 +++ b/test/integration/test-apt-ftparchive-cachedb-lp1274466 @@ -46,6 +46,8 @@ Description: an autogenerated dummy foo=1/test " aptftparchive --db old-format.db packages . # ensure that the db is updated and contains the new sha512 +db_dump old-format.db > old-format.dump + testsuccess grep 7da58ff901a40ecf42a730dc33198b182e9ba9ec98799fc2c2b6fabeeee40cc12a0e7cadb4b66764235c56e1009dbfe8a9a566fb1eedf47a992d1fff2cc3332c old-format.dump -- cgit v1.2.3-70-g09d2 From 3c528b911af131028486d4873d5dcbd0682ed15e Mon Sep 17 00:00:00 2001 From: Michele Orrù Date: Mon, 7 Jul 2014 20:48:16 +0200 Subject: use printf instead of echo in testing framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The behaviour of echo "\tA\t" differs between dash/zsh which interprets the \t as tab and bash which prints it literally. Similar things happen for other escape sequences – without the -e flag. Switching to printf makes this more painless^Wportable, so that the tests are also working correctly with bash as sh. (commit message by committer, patch otherwise unmodified) --- test/integration/framework | 58 +++++++++++++++++++++++----------------------- test/integration/run-tests | 4 ++-- 2 files changed, 31 insertions(+), 31 deletions(-) (limited to 'test/integration/framework') diff --git a/test/integration/framework b/test/integration/framework index a687dcb35..3bbf440c8 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -23,30 +23,30 @@ if [ "$MSGCOLOR" != 'NO' ]; then CCMD="\033[1;35m" # pink fi -msgdie() { echo "${CERROR}E: $1${CNORMAL}" >&2; exit 1; } -msgwarn() { echo "${CWARNING}W: $1${CNORMAL}" >&2; } -msgmsg() { echo "${CMSG}$1${CNORMAL}"; } -msginfo() { echo "${CINFO}I: $1${CNORMAL}"; } -msgdebug() { echo "${CDEBUG}D: $1${CNORMAL}"; } -msgdone() { echo "${CDONE}DONE${CNORMAL}"; } -msgnwarn() { echo -n "${CWARNING}W: $1${CNORMAL}" >&2; } -msgnmsg() { echo -n "${CMSG}$1${CNORMAL}"; } -msgninfo() { echo -n "${CINFO}I: $1${CNORMAL}"; } -msgndebug() { echo -n "${CDEBUG}D: $1${CNORMAL}"; } +msgdie() { printf "${CERROR}E: $1${CNORMAL}\n" >&2; exit 1; } +msgwarn() { printf "${CWARNING}W: $1${CNORMAL}\n" >&2; } +msgmsg() { printf "${CMSG}$1${CNORMAL}\n"; } +msginfo() { printf "${CINFO}I: $1${CNORMAL}\n"; } +msgdebug() { printf "${CDEBUG}D: $1${CNORMAL}\n"; } +msgdone() { printf "${CDONE}DONE${CNORMAL}\n"; } +msgnwarn() { printf "${CWARNING}W: $1${CNORMAL}" >&2; } +msgnmsg() { printf "${CMSG}$1${CNORMAL}"; } +msgninfo() { printf "${CINFO}I: $1${CNORMAL}"; } +msgndebug() { printf "${CDEBUG}D: $1${CNORMAL}"; } msgtest() { while [ -n "$1" ]; do - echo -n "${CINFO}$1${CCMD} " - echo -n "$(echo "$2" | sed -e 's#^apt\([cgfs]\)#apt-\1#')${CINFO} " + printf "${CINFO}$1${CCMD} " + printf -- "$(echo "$2" | sed -e 's#^apt\([cgfs]\)#apt-\1#')${CINFO} " shift if [ -n "$1" ]; then shift; else break; fi done - echo -n "…${CNORMAL} " + printf "…${CNORMAL} " } -msgpass() { echo "${CPASS}PASS${CNORMAL}"; } -msgskip() { echo "${CWARNING}SKIP${CNORMAL}" >&2; } +msgpass() { printf "${CPASS}PASS${CNORMAL}\n"; } +msgskip() { printf "${CWARNING}SKIP${CNORMAL}\n" >&2; } msgfail() { - if [ $# -gt 0 ]; then echo "${CFAIL}FAIL: $*${CNORMAL}" >&2; - else echo "${CFAIL}FAIL${CNORMAL}" >&2; fi + if [ $# -gt 0 ]; then printf "${CFAIL}FAIL: $*${CNORMAL}\n" >&2; + else printf "${CFAIL}FAIL${CNORMAL}\n" >&2; fi EXIT_CODE=$((EXIT_CODE+1)); } @@ -63,12 +63,12 @@ if [ $MSGLEVEL -le 2 ]; then msgmsg() { true; } msgnmsg() { true; } msgtest() { true; } - msgpass() { echo -n " ${CPASS}P${CNORMAL}"; } - msgskip() { echo -n " ${CWARNING}S${CNORMAL}" >&2; } + msgpass() { printf " ${CPASS}P${CNORMAL}"; } + msgskip() { printf " ${CWARNING}S${CNORMAL}" >&2; } if [ -n "$CFAIL" ]; then - msgfail() { echo -n " ${CFAIL}FAIL${CNORMAL}" >&2; EXIT_CODE=$((EXIT_CODE+1)); } + msgfail() { printf " ${CFAIL}FAIL${CNORMAL}" >&2; EXIT_CODE=$((EXIT_CODE+1)); } else - msgfail() { echo -n " ###FAILED###" >&2; EXIT_CODE=$((EXIT_CODE+1)); } + msgfail() { printf " ###FAILED###" >&2; EXIT_CODE=$((EXIT_CODE+1)); } fi fi if [ $MSGLEVEL -le 3 ]; then @@ -87,7 +87,7 @@ msgdone() { [ "$1" = "die" -a $MSGLEVEL -le 0 ]; then true; else - echo "${CDONE}DONE${CNORMAL}"; + printf "${CDONE}DONE${CNORMAL}\n"; fi } getaptconfig() { @@ -155,7 +155,7 @@ exitwithstatus() { shellsetedetector() { local exit_status=$? if [ "$exit_status" != '0' ]; then - echo >&2 "${CERROR}E: Looks like the testcases ended prematurely with exitcode: ${exit_status}${CNORMAL}" + printf >&2 "${CERROR}E: Looks like the testcases ended prematurely with exitcode: ${exit_status}${CNORMAL}\n" if [ "$EXIT_CODE" = '0' ]; then EXIT_CODE="$exit_status" fi @@ -328,12 +328,12 @@ configdpkg() { configcompression() { while [ -n "$1" ]; do case "$1" in - '.') echo ".\t.\tcat";; - 'gz') echo "gzip\tgz\tgzip";; - 'bz2') echo "bzip2\tbz2\tbzip2";; - 'lzma') echo "lzma\tlzma\txz --format=lzma";; - 'xz') echo "xz\txz\txz";; - *) echo "$1\t$1\t$1";; + '.') printf ".\t.\tcat\n";; + 'gz') printf "gzip\tgz\tgzip\n";; + 'bz2') printf "bzip2\tbz2\tbzip2\n";; + 'lzma') printf "lzma\tlzma\txz --format=lzma\n";; + 'xz') printf "xz\txz\txz\n";; + *) printf "$1\t$1\t$1\n";; esac shift done > ${TMPWORKINGDIRECTORY}/rootdir/etc/testcase-compressor.conf diff --git a/test/integration/run-tests b/test/integration/run-tests index d39daeee5..9dd550aa2 100755 --- a/test/integration/run-tests +++ b/test/integration/run-tests @@ -39,9 +39,9 @@ fi TOTAL="$(run-parts --list $DIR | grep '/test-' | wc -l)" for testcase in $(run-parts --list $DIR | grep '/test-'); do if [ "$MSGLEVEL" -le 2 ]; then - echo -n "($(($ALL+1))/${TOTAL}) ${CTEST}Testcase ${CHIGH}$(basename ${testcase})${CRESET}: " + printf "($(($ALL+1))/${TOTAL}) ${CTEST}Testcase ${CHIGH}$(basename ${testcase})${CRESET}: " else - echo "${CTEST}Run Testcase ($(($ALL+1))/${TOTAL}) ${CHIGH}$(basename ${testcase})${CRESET}" + printf "${CTEST}Run Testcase ($(($ALL+1))/${TOTAL}) ${CHIGH}$(basename ${testcase})${CRESET}\n" fi if ! ${testcase}; then FAIL=$((FAIL+1)) -- cgit v1.2.3-70-g09d2 From 859093dae7dcadaff2e15a3885a1824b0d5f5913 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sat, 30 Aug 2014 11:29:45 +0200 Subject: support regular expressions in 'apt search' apt-cache search supported this since ever and in the code for apt was a fixme indicating this should be added here as well, so here we go. --- apt-private/private-cmndline.cc | 9 +++++-- apt-private/private-search.cc | 52 ++++++++++++++++++++++++------------ test/integration/framework | 8 +++++- test/integration/test-apt-cli-search | 15 +++++++++++ 4 files changed, 64 insertions(+), 20 deletions(-) (limited to 'test/integration/framework') diff --git a/apt-private/private-cmndline.cc b/apt-private/private-cmndline.cc index a21a9dc8c..a4490f5b4 100644 --- a/apt-private/private-cmndline.cc +++ b/apt-private/private-cmndline.cc @@ -70,6 +70,8 @@ static bool addArgumentsAPTCache(std::vector &Args, char cons else return false; + bool const found_something = Args.empty() == false; + // FIXME: move to the correct command(s) addArg('g', "generate", "APT::Cache::Generate", 0); addArg('t', "target-release", "APT::Default-Release", CommandLine::HasArg); @@ -77,7 +79,8 @@ static bool addArgumentsAPTCache(std::vector &Args, char cons addArg('p', "pkg-cache", "Dir::Cache::pkgcache", CommandLine::HasArg); addArg('s', "src-cache", "Dir::Cache::srcpkgcache", CommandLine::HasArg); - return true; + + return found_something; } /*}}}*/ static bool addArgumentsAPTCDROM(std::vector &Args, char const * const Cmd)/*{{{*/ @@ -172,6 +175,8 @@ static bool addArgumentsAPTGet(std::vector &Args, char const addArg('s', "no-act", "APT::Get::Simulate", 0); } + bool const found_something = Args.empty() == false; + // FIXME: move to the correct command(s) addArg('d',"download-only","APT::Get::Download-Only",0); addArg('y',"yes","APT::Get::Assume-Yes",0); @@ -197,7 +202,7 @@ static bool addArgumentsAPTGet(std::vector &Args, char const addArg(0,"install-suggests","APT::Install-Suggests",CommandLine::Boolean); addArg(0,"fix-policy","APT::Get::Fix-Policy-Broken",0); - return true; + return found_something; } /*}}}*/ static bool addArgumentsAPTMark(std::vector &Args, char const * const Cmd)/*{{{*/ diff --git a/apt-private/private-search.cc b/apt-private/private-search.cc index ecd5d7fad..2230c973a 100644 --- a/apt-private/private-search.cc +++ b/apt-private/private-search.cc @@ -36,8 +36,28 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/ if (unlikely(Cache == NULL || Plcy == NULL)) return false; - const char **patterns; - patterns = CmdL.FileList + 1; + // Make sure there is at least one argument + unsigned int const NumPatterns = CmdL.FileSize() -1; + if (NumPatterns < 1) + return _error->Error(_("You must give at least one search pattern")); + +#define APT_FREE_PATTERNS() for (std::vector::iterator P = Patterns.begin(); \ + P != Patterns.end(); ++P) { regfree(&(*P)); } + + // Compile the regex pattern + std::vector Patterns; + for (unsigned int I = 0; I != NumPatterns; ++I) + { + regex_t pattern; + if (regcomp(&pattern, CmdL.FileList[I + 1], REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0) + { + APT_FREE_PATTERNS(); + return _error->Error("Regex compilation error"); + } + Patterns.push_back(pattern); + } + + bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly", false); std::map output_map; std::map::const_iterator K; @@ -56,26 +76,23 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/ if (Done%500 == 0) progress.Progress(Done); ++Done; - - int i; + pkgCache::DescIterator Desc = V.TranslatedDescription(); pkgRecords::Parser &parser = records.Lookup(Desc.FileList()); - + bool all_found = true; - for(i=0; patterns[i] != NULL; ++i) + for (std::vector::const_iterator pattern = Patterns.begin(); + pattern != Patterns.end(); ++pattern) { - // FIXME: use regexp instead of simple find() - const char *pattern = patterns[i]; - all_found &= ( - strstr(V.ParentPkg().Name(), pattern) != NULL || - strcasestr(parser.ShortDesc().c_str(), pattern) != NULL || - strcasestr(parser.LongDesc().c_str(), pattern) != NULL); - // search patterns are AND by default so we can skip looking further - // on the first mismatch - if(all_found == false) - break; + if (regexec(&(*pattern), V.ParentPkg().Name(), 0, 0, 0) == 0) + continue; + else if (NamesOnly == false && regexec(&(*pattern), parser.LongDesc().c_str(), 0, 0, 0) == 0) + continue; + // search patterns are AND, so one failing fails all + all_found = false; + break; } - if (all_found) + if (all_found == true) { std::stringstream outs; ListSingleVersion(CacheFile, records, V, outs); @@ -83,6 +100,7 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/ V.ParentPkg().Name(), outs.str())); } } + APT_FREE_PATTERNS(); progress.Done(); // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status) diff --git a/test/integration/framework b/test/integration/framework index 3bbf440c8..fde74f55d 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -1019,7 +1019,13 @@ testfileequal() { testempty() { msgtest "Test for no output of" "$*" - test -z "$($* 2>&1)" && msgpass || msgfail + local COMPAREFILE="${TMPWORKINGDIRECTORY}/rootdir/tmp/testempty.comparefile" + if $* >$COMPAREFILE 2>&1 && test ! -s $COMPAREFILE; then + msgpass + else + cat $COMPAREFILE + msgfail + fi } testequal() { diff --git a/test/integration/test-apt-cli-search b/test/integration/test-apt-cli-search index 58613717b..3ac074952 100755 --- a/test/integration/test-apt-cli-search +++ b/test/integration/test-apt-cli-search @@ -33,16 +33,31 @@ foo/unstable 1.0 all testequal "foo/unstable 1.0 all $DESCR " apt search -qq xxyyzz +testempty apt search -qq --names-only xxyyzz + +# search name +testequal "foo/unstable 1.0 all + $DESCR +" apt search -qq foo +testequal "foo/unstable 1.0 all + $DESCR +" apt search -qq --names-only foo # search with multiple words is a AND search testequal "foo/unstable 1.0 all $DESCR " apt search -qq aabbcc xxyyzz +testequal "foo/unstable 1.0 all + $DESCR +" apt search -qq 'a+b+c+' 'i*xxy{0,2}zz' # search is not case-sensitive by default testequal "foo/unstable 1.0 all $DESCR " apt search -qq uppercase +testequal "foo/unstable 1.0 all + $DESCR +" apt search -qq 'up[pP]erc[Aa]se' # output is sorted and search word finds both package testequal "bar/testing 2.0 i386 -- cgit v1.2.3-70-g09d2 From 27cb4f6c919921b04f3dddff069620ced250a94f Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 7 Sep 2014 19:30:33 +0200 Subject: detect terminal output with 'test -t' in tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of trying to inspect /proc and the fds inside we use "test -t 1" instead as this is available and working on kfreebsd as well – not that something breaks if we wouldn't, but we like color. Git-Dch: Ignore --- test/integration/framework | 2 +- test/integration/run-tests | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'test/integration/framework') diff --git a/test/integration/framework b/test/integration/framework index fde74f55d..ff010a5c4 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -4,7 +4,7 @@ EXIT_CODE=0 # we all like colorful messages if [ "$MSGCOLOR" != 'NO' ]; then - if ! expr match "$(readlink -f /proc/$$/fd/1)" '/dev/pts/[0-9]\+' > /dev/null; then + if [ ! -t 1 ]; then # but check that we output to a terminal export MSGCOLOR='NO' fi fi diff --git a/test/integration/run-tests b/test/integration/run-tests index 9dd550aa2..c39a2ac68 100755 --- a/test/integration/run-tests +++ b/test/integration/run-tests @@ -22,7 +22,7 @@ done export MSGLEVEL="${MSGLEVEL:-3}" if [ "$MSGCOLOR" != 'NO' ]; then - if ! expr match "$(readlink -f /proc/$$/fd/1)" '/dev/pts/[0-9]\+' > /dev/null; then + if [ ! -t 1 ]; then # but check that we output to a terminal export MSGCOLOR='NO' fi fi -- cgit v1.2.3-70-g09d2 From 5f982b9d903b38bb5549479f0111d31e2695090c Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Thu, 25 Sep 2014 11:52:41 +0200 Subject: rewrite compressed indexes test to check with all compressors Git-Dch: Ignore --- test/integration/framework | 30 ++++ .../test-bug-595691-empty-and-broken-archive-files | 33 +--- test/integration/test-compressed-indexes | 194 +++++++++++---------- 3 files changed, 135 insertions(+), 122 deletions(-) (limited to 'test/integration/framework') diff --git a/test/integration/framework b/test/integration/framework index ff010a5c4..7923e23d9 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -339,6 +339,36 @@ configcompression() { done > ${TMPWORKINGDIRECTORY}/rootdir/etc/testcase-compressor.conf } +forcecompressor() { + COMPRESSOR="$1" + COMPRESSOR_CMD="$1" + case $COMPRESSOR in + gzip) COMPRESS='gz';; + bzip2) COMPRESS='bz2';; + lzma) COMPRESS='lzma';; + xz) COMPRESS='xz';; + *) msgdie "Compressor $COMPRESSOR is unknown to framework, so can't be forced by forcecompressor!";; + esac + local CONFFILE="${TMPWORKINGDIRECTORY}/rootdir/etc/apt/apt.conf.d/00force-compressor" + echo "Acquire::CompressionTypes::Order { \"${COMPRESS}\"; }; +Dir::Bin::uncompressed \"/does/not/exist\"; +Dir::Bin::gzip \"/does/not/exist\"; +Dir::Bin::bzip2 \"/does/not/exist\"; +Dir::Bin::lzma \"/does/not/exist\"; +Dir::Bin::xz \"/does/not/exist\";" > "$CONFFILE" + if [ -e "/bin/${COMPRESSOR}" ]; then + echo "Dir::Bin::${COMPRESSOR} \"/bin/${COMPRESSOR}\";" >> "$CONFFILE" + elif [ -e "/usr/bin/${COMPRESSOR}" ]; then + echo "Dir::Bin::${COMPRESSOR} \"/usr/bin/${COMPRESSOR}\";" >> "$CONFFILE" + elif [ "${COMPRESSOR}" = 'lzma' ]; then + echo 'Dir::Bin::xz "/usr/bin/xz";' >> "$CONFFILE" + COMPRESSOR_CMD='xz --format=lzma' + else + msgtest 'Test for availability of compressor' "${COMPRESSOR}" + msgfail + fi +} + setupsimplenativepackage() { local NAME="$1" local ARCH="$2" diff --git a/test/integration/test-bug-595691-empty-and-broken-archive-files b/test/integration/test-bug-595691-empty-and-broken-archive-files index 23a638801..aea340203 100755 --- a/test/integration/test-bug-595691-empty-and-broken-archive-files +++ b/test/integration/test-bug-595691-empty-and-broken-archive-files @@ -48,37 +48,8 @@ createemptyfile() { rm -f aptarchive/Packages } -setupcompressor() { - COMPRESSOR="$1" - COMPRESSOR_CMD="$1" - case $COMPRESSOR in - gzip) COMPRESS="gz";; - bzip2) COMPRESS="bz2";; - lzma) COMPRESS="lzma";; - xz) COMPRESS="xz";; - esac - echo "Acquire::CompressionTypes::Order { \"${COMPRESS}\"; }; -Dir::Bin::uncompressed \"/does/not/exist\"; -Dir::Bin::gzip \"/does/not/exist\"; -Dir::Bin::bzip2 \"/does/not/exist\"; -Dir::Bin::lzma \"/does/not/exist\"; -Dir::Bin::xz \"/does/not/exist\";" > rootdir/etc/apt/apt.conf.d/00compressor - if [ -e "/bin/${COMPRESSOR}" ]; then - echo "Dir::Bin::${COMPRESSOR} \"/bin/${COMPRESSOR}\";" >> rootdir/etc/apt/apt.conf.d/00compressor - elif [ -e "/usr/bin/${COMPRESSOR}" ]; then - echo "Dir::Bin::${COMPRESSOR} \"/usr/bin/${COMPRESSOR}\";" >> rootdir/etc/apt/apt.conf.d/00compressor - elif [ "${COMPRESSOR}" = 'lzma' ]; then - echo "Dir::Bin::xz \"/usr/bin/xz\";" >> rootdir/etc/apt/apt.conf.d/00compressor - COMPRESSOR_CMD='xz --format=lzma' - else - msgtest "Test for availability of compressor" "${COMPRESSOR}" - msgfail - #exit 1 - fi -} - testoverfile() { - setupcompressor "$1" + forcecompressor "$1" createemptyfile 'en' testaptgetupdate 'Reading package lists...' "empty file en.$COMPRESS over file" @@ -100,7 +71,7 @@ E: Some index files failed to download. They have been ignored, or old ones used } testoverhttp() { - setupcompressor "$1" + forcecompressor "$1" createemptyfile 'en' testaptgetupdate "Get: http://localhost:8080 Packages [] diff --git a/test/integration/test-compressed-indexes b/test/integration/test-compressed-indexes index 819cbd35e..805ed5964 100755 --- a/test/integration/test-compressed-indexes +++ b/test/integration/test-compressed-indexes @@ -5,53 +5,68 @@ TESTDIR=$(readlink -f $(dirname $0)) . $TESTDIR/framework setupenvironment -configcompression '.' 'xz' 'gz' -configarchitecture "i386" - -buildsimplenativepackage "testpkg" "i386" "1.0" -setupaptarchive - -GOODSHOW="$(aptcache show testpkg) -" -GOODPOLICY="$(aptcache policy testpkg)" -GOODSHOWSRC="$(aptcache showsrc testpkg) -" - -test $(echo "$GOODSHOW" | grep -e '^Package: testpkg' -e '^Version: 1.0' -e '^Architecture: i386' | wc -l) -eq 3 || msgdie 'show is broken' -testequal "$GOODSHOW" aptcache show testpkg -test $(echo "$GOODPOLICY" | grep -e '^testpkg:' -e '^ Candidate:' -e '^ Installed: (none)' -e '500 file:/' | wc -l) -eq 4 || msgdie 'policy is broken' -testequal "$GOODPOLICY" aptcache policy testpkg -test $(echo "$GOODSHOWSRC" | grep -e '^Package: testpkg' -e '^Format: 3.0 (native)' -e '^Files:' -e '^Checksums-Sha256:' | wc -l) -eq 4 || msgdie 'showsrc is broken' -testequal "$GOODSHOWSRC" aptcache showsrc testpkg - +configcompression '.' 'xz' 'bz2' 'lzma' 'gz' +configarchitecture 'i386' + +buildsimplenativepackage 'testpkg' 'i386' '1.0' + +buildaptarchive +setupdistsaptarchive +# fake a pdiff setup as apt wouldn't try pdiffs otherwise +find aptarchive -name 'Packages' -o -name 'Sources' | while read file; do + mkdir "${file}.diff" + PATCHINDEX="${file}.diff/Index" + echo 'SHA1-Current: adc83b19e793491b1c6ea0fd8b46cd9f32e592fc 0 +SHA1-History: + adc83b19e793491b1c6ea0fd8b46cd9f32e592fc 33053002 2010-08-18-2013.28 + ecfd1b19e793491b1c6ea123eabdcd9f32e592fc 33053001 2010-08-18-2013.29 +SHA1-Patches: + abc1fc0ac57cd83d41c63195a9342e2db5650257 19722 2010-08-18-0814.28 + dfe3444ac57cd83d41c63195a9342e2db5650257 19722 2010-08-18-0814.29' > $PATCHINDEX +done +generatereleasefiles +signreleasefiles testrun() { local F - if [ -e rootdir/var/lib/apt/lists/*localhost*Release ]; then - msgtest "Check if all index files are" "${1:-uncompressed}" - if [ "$1" = "compressed" ]; then - ! test -e rootdir/var/lib/apt/lists/*_Packages || F=1 - ! test -e rootdir/var/lib/apt/lists/*_Sources || F=1 - test -e rootdir/var/lib/apt/lists/*_Packages.xz || F=1 - test -e rootdir/var/lib/apt/lists/*_Sources.xz || F=1 - else - test -e rootdir/var/lib/apt/lists/*_Packages || F=1 - test -e rootdir/var/lib/apt/lists/*_Sources || F=1 - ! test -e rootdir/var/lib/apt/lists/*_Packages.xz || F=1 - ! test -e rootdir/var/lib/apt/lists/*_Sources.xz || F=1 - fi - if [ -n "$F" ]; then - ls -laR rootdir/var/lib/apt/lists/ - msgfail - else - msgpass - fi - msgtest "Check if package is downloadable" - testsuccess --nomsg aptget install -d testpkg - msgtest "\tdeb file is present"; testsuccess --nomsg test -f rootdir/var/cache/apt/archives/testpkg_1.0_i386.deb - aptget clean - msgtest "\tdeb file is gone"; testfailure --nomsg test -f rootdir/var/cache/apt/archives/testpkg_1.0_i386.deb + msgtest 'Check if all index files are' "${1:-uncompressed}" + if [ "$1" = 'compressed' ]; then + ! test -e rootdir/var/lib/apt/lists/*_Packages || F=1 + ! test -e rootdir/var/lib/apt/lists/*_Sources || F=1 + ! test -e rootdir/var/lib/apt/lists/*_Translation-en || F=1 + test -e rootdir/var/lib/apt/lists/*_Packages.${COMPRESS} || F=1 + test -e rootdir/var/lib/apt/lists/*_Sources.${COMPRESS} || F=1 + test -e rootdir/var/lib/apt/lists/*_Translation-en.${COMPRESS} || F=1 + # there is no point in trying pdiff if we have compressed indexes + # as we can't patch compressed files (well, we can, but what is the point?) + ! test -e rootdir/var/lib/apt/lists/*.IndexDiff || F=1 + else + # clear the faked pdiff indexes so the glob below works + rm -f rootdir/var/lib/apt/lists/*.IndexDiff + test -e rootdir/var/lib/apt/lists/*_Packages || F=1 + test -e rootdir/var/lib/apt/lists/*_Sources || F=1 + test -e rootdir/var/lib/apt/lists/*_Translation-en || F=1 + ! test -e rootdir/var/lib/apt/lists/*_Packages.* || F=1 + ! test -e rootdir/var/lib/apt/lists/*_Sources.* || F=1 + ! test -e rootdir/var/lib/apt/lists/*_Translation-en.* || F=1 fi + if [ -n "$F" ]; then + ls -laR rootdir/var/lib/apt/lists/ + msgfail + else + msgpass + fi + msgtest 'Check if package is downloadable' + testsuccess --nomsg aptget download testpkg + msgtest '\tdeb file is present'; testsuccess --nomsg test -f testpkg_1.0_i386.deb + rm testpkg_1.0_i386.deb + testequal 'Reading package lists... +Building dependency tree... +The following NEW packages will be installed: + testpkg +0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded. +Inst testpkg (1.0 unstable [i386]) +Conf testpkg (1.0 unstable [i386])' aptget install testpkg -s rm -f rootdir/var/cache/apt/pkgcache.bin rootdir/var/cache/apt/srcpkgcache.bin testequal "$GOODSHOW" aptcache show testpkg testequal "$GOODSHOW" aptcache show testpkg @@ -62,71 +77,68 @@ testrun() { testequal "$GOODSHOWSRC" aptcache showsrc testpkg testequal "$GOODSHOWSRC" aptcache showsrc testpkg aptget clean - msgtest "Check if the source is aptgetable" + msgtest 'Check if the source is aptgetable' testsuccess --nomsg aptget source testpkg - msgtest "\tdsc file is present"; testsuccess --nomsg test -f testpkg_1.0.dsc - msgtest "\tdirectory is present"; testsuccess --nomsg test -d testpkg-1.0 - rm -rf testpkg-1.0 + msgtest '\tdsc file is present'; testsuccess --nomsg test -f testpkg_1.0.dsc + msgtest '\tdirectory is present'; testsuccess --nomsg test -d testpkg-1.0 + rm -rf testpkg-1.0* testequal "$(aptcache show testpkg -o Acquire::Languages=none) " aptcache dumpavail } -echo 'Acquire::GzipIndexes "false";' > rootdir/etc/apt/apt.conf.d/02compressindex -msgmsg "File: Test with uncompressed indexes" -testrun +echo 'Debug::pkgAcquire::worker "true"; +debug::pkgAcquire::Auth "true"; +Debug::pkgAcquire::Diffs "true";' > rootdir/etc/apt/apt.conf.d/99debugconf -testsuccess aptget update -o Acquire::Pdiffs=1 -msgmsg "File: Test with uncompressed indexes (update unchanged with pdiffs)" -testrun +testovermethod() { + forcecompressor $2 -testsuccess aptget update -o Acquire::Pdiffs=0 -msgmsg "File: Test with uncompressed indexes (update unchanged without pdiffs)" -testrun + for INDEX in 'false' 'true'; do + rm -rf rootdir/var/lib/apt/lists + echo "Acquire::GzipIndexes \"${INDEX}\";" > rootdir/etc/apt/apt.conf.d/02compressindex + local INDCOMP + if [ "$INDEX" = 'false' ]; then + INDCOMP='uncompressed' + else + INDCOMP='compressed' + fi -rm -rf rootdir/var/lib/apt/lists -echo 'Acquire::GzipIndexes "true";' > rootdir/etc/apt/apt.conf.d/02compressindex + testsuccess aptget update + msgmsg "${1}: ${COMPRESSOR}: Test with $INDCOMP indexes" + testrun "$INDCOMP" -testsuccess aptget update -o Debug::pkgAcquire::worker=1 -msgmsg "File: Test with compressed indexes" -testrun "compressed" + testsuccess aptget update -o Acquire::Pdiffs=1 + msgmsg "${1}: ${COMPRESSOR}: Test with $INDCOMP indexes (update unchanged with pdiffs)" + testrun "$INDCOMP" -testsuccess aptget update -o Acquire::Pdiffs=1 -msgmsg "File: Test with compressed indexes (update unchanged with pdiffs)" -testrun "compressed" + testsuccess aptget update -o Acquire::Pdiffs=0 + msgmsg "${1}: ${COMPRESSOR}: Test with $INDCOMP indexes (update unchanged without pdiffs)" + testrun "$INDCOMP" -testsuccess aptget update -o Acquire::Pdiffs=0 -msgmsg "File: Test with compressed indexes (update unchanged without pdiffs)" -testrun "compressed" + rm rootdir/etc/apt/apt.conf.d/02compressindex + done +} -rm rootdir/etc/apt/apt.conf.d/02compressindex -changetowebserver testsuccess aptget update +GOODSHOW="$(aptcache show testpkg) +" +test $(echo "$GOODSHOW" | grep -e '^Package: testpkg' -e '^Version: 1.0' -e '^Architecture: i386' | wc -l) -eq 3 || msgdie 'show is broken' +testequal "$GOODSHOW" aptcache show testpkg +GOODSHOWSRC="$(aptcache showsrc testpkg) +" +test $(echo "$GOODSHOWSRC" | grep -e '^Package: testpkg' -e '^Format: 3.0 (native)' -e '^Files:' -e '^Checksums-Sha256:' | wc -l) -eq 4 || msgdie 'showsrc is broken' +testequal "$GOODSHOWSRC" aptcache showsrc testpkg GOODPOLICY="$(aptcache policy testpkg)" -test $(echo "$GOODPOLICY" | grep -e '^testpkg:' -e '^ Candidate:' -e '^ Installed: (none)' -e '500 http://' | wc -l) -eq 4 +test $(echo "$GOODPOLICY" | grep -e '^testpkg:' -e '^ Candidate:' -e '^ Installed: (none)' -e '500 file:/' | wc -l) -eq 4 || msgdie 'policy is broken' testequal "$GOODPOLICY" aptcache policy testpkg -msgmsg "HTTP: Test with uncompressed indexes" -testrun - -testsuccess aptget update -o Acquire::Pdiffs=1 -msgmsg "HTTP: Test with uncompressed indexes (update unchanged with pdiffs)" -testrun - -testsuccess aptget update -o Acquire::Pdiffs=0 -msgmsg "HTTP: Test with uncompressed indexes (update unchanged without pdiffs)" -testrun +for COMPRESSOR in 'gzip' 'bzip2' 'lzma' 'xz'; do testovermethod 'file' $COMPRESSOR; done +changetowebserver rm -rf rootdir/var/lib/apt/lists -echo 'Acquire::GzipIndexes "true";' > rootdir/etc/apt/apt.conf.d/02compressindex - testsuccess aptget update -msgmsg "HTTP: Test with compressed indexes" -testrun "compressed" - -testsuccess aptget update -o Acquire::Pdiffs=1 -o debug::pkgAcquire::Worker=1 -o debug::pkgAcquire::Auth=1 -msgmsg "HTTP: Test with compressed indexes (update unchanged with pdiffs)" -testrun "compressed" +GOODPOLICY="$(aptcache policy testpkg)" +test $(echo "$GOODPOLICY" | grep -e '^testpkg:' -e '^ Candidate:' -e '^ Installed: (none)' -e '500 http://' | wc -l) -eq 4 || msgdie 'policy is broken' +testequal "$GOODPOLICY" aptcache policy testpkg -testsuccess aptget update -o Acquire::Pdiffs=0 -msgmsg "HTTP: Test with compressed indexes (update unchanged without pdiffs)" -testrun "compressed" +for COMPRESSOR in 'gzip' 'bzip2' 'lzma' 'xz'; do testovermethod 'http' $COMPRESSOR; done -- cgit v1.2.3-70-g09d2 From 12841e8320aa499554ac50b102b222900bb1b879 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 24 Jan 2014 23:48:11 +0100 Subject: use apt-key adv (+ gnupg) instead of gpgv for verify apt-key does the keyring merge as we need it, so we just call it instead of reimplementing it to do the merging before gpgv. This means we don't use gpgv anymore (we never depended on it explicitly - bad style), but it also means that the message in apt-cdrom add is a bit less friendly as it says loudly "untrusted key", but for a one-time command its okay. --- apt-pkg/contrib/gpgv.cc | 63 +++++++--------------- test/integration/framework | 1 + test/integration/test-apt-cdrom | 2 +- test/integration/test-apt-key-net-update | 7 ++- .../integration/test-bug-733028-gpg-resource-limit | 27 ++++++++++ 5 files changed, 53 insertions(+), 47 deletions(-) create mode 100755 test/integration/test-bug-733028-gpg-resource-limit (limited to 'test/integration/framework') diff --git a/apt-pkg/contrib/gpgv.cc b/apt-pkg/contrib/gpgv.cc index f24dd9640..56e26ab99 100644 --- a/apt-pkg/contrib/gpgv.cc +++ b/apt-pkg/contrib/gpgv.cc @@ -32,50 +32,29 @@ static char * GenerateTemporaryFileTemplate(const char *basename) /*{{{*/ /*}}}*/ // ExecGPGV - returns the command needed for verify /*{{{*/ // --------------------------------------------------------------------- -/* Generating the commandline for calling gpgv is somehow complicated as +/* Generating the commandline for calling gpg is somehow complicated as we need to add multiple keyrings and user supplied options. - Also, as gpgv has no options to enforce a certain reduced style of + Also, as gpg has no options to enforce a certain reduced style of clear-signed files (=the complete content of the file is signed and the content isn't encoded) we do a divide and conquer approach here - and split up the clear-signed file in message and signature for gpgv + and split up the clear-signed file in message and signature for gpg. + And as a cherry on the cake, we use our apt-key wrapper to do part + of the lifting in regards to merging keyrings. Fun for the whole family. */ void ExecGPGV(std::string const &File, std::string const &FileGPG, int const &statusfd, int fd[2]) { #define EINTERNAL 111 - std::string const gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv"); - // FIXME: remove support for deprecated APT::GPGV setting - std::string const trustedFile = _config->Find("APT::GPGV::TrustedKeyring", _config->FindFile("Dir::Etc::Trusted")); - std::string const trustedPath = _config->FindDir("Dir::Etc::TrustedParts"); + std::string const aptkey = _config->FindFile("Dir::Bin::apt-key", "/usr/bin/apt-key"); bool const Debug = _config->FindB("Debug::Acquire::gpgv", false); - if (Debug == true) - { - std::clog << "gpgv path: " << gpgvpath << std::endl; - std::clog << "Keyring file: " << trustedFile << std::endl; - std::clog << "Keyring path: " << trustedPath << std::endl; - } - - std::vector keyrings; - if (DirectoryExists(trustedPath)) - keyrings = GetListOfFilesInDir(trustedPath, "gpg", false, true); - if (RealFileExists(trustedFile) == true) - keyrings.push_back(trustedFile); - std::vector Args; - Args.reserve(30); - - if (keyrings.empty() == true) - { - // TRANSLATOR: %s is the trusted keyring parts directory - ioprintf(std::cerr, _("No keyring installed in %s."), - _config->FindDir("Dir::Etc::TrustedParts").c_str()); - exit(EINTERNAL); - } + Args.reserve(10); - Args.push_back(gpgvpath.c_str()); - Args.push_back("--ignore-time-conflict"); + Args.push_back(aptkey.c_str()); + Args.push_back("--quiet"); + Args.push_back("adv"); char statusfdstr[10]; if (statusfd != -1) @@ -85,13 +64,6 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, Args.push_back(statusfdstr); } - for (std::vector::const_iterator K = keyrings.begin(); - K != keyrings.end(); ++K) - { - Args.push_back("--keyring"); - Args.push_back(K->c_str()); - } - Configuration::Item const *Opts; Opts = _config->Tree("Acquire::gpgv::Options"); if (Opts != 0) @@ -104,6 +76,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, Args.push_back(Opts->Value.c_str()); } } + Args.push_back("--verify"); enum { DETACHED, CLEARSIGNED } releaseSignature = (FileGPG != File) ? DETACHED : CLEARSIGNED; std::vector dataHeader; @@ -160,7 +133,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, if (Debug == true) { - std::clog << "Preparing to exec: " << gpgvpath; + std::clog << "Preparing to exec: "; for (std::vector::const_iterator a = Args.begin(); *a != NULL; ++a) std::clog << " " << *a; std::clog << std::endl; @@ -168,7 +141,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, if (statusfd != -1) { - int const nullfd = open("/dev/null", O_RDONLY); + int const nullfd = open("/dev/null", O_WRONLY); close(fd[0]); // Redirect output to /dev/null; we read from the status fd if (statusfd != STDOUT_FILENO) @@ -185,7 +158,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, if (releaseSignature == DETACHED) { - execvp(gpgvpath.c_str(), (char **) &Args[0]); + execvp(Args[0], (char **) &Args[0]); ioprintf(std::cerr, "Couldn't execute %s to check %s", Args[0], File.c_str()); exit(EINTERNAL); } @@ -205,7 +178,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, { if (statusfd != -1) dup2(fd[1], statusfd); - execvp(gpgvpath.c_str(), (char **) &Args[0]); + execvp(Args[0], (char **) &Args[0]); ioprintf(std::cerr, "Couldn't execute %s to check %s", Args[0], File.c_str()); UNLINK_EXIT(EINTERNAL); } @@ -216,7 +189,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, { if (errno == EINTR) continue; - ioprintf(std::cerr, _("Waited for %s but it wasn't there"), "gpgv"); + ioprintf(std::cerr, _("Waited for %s but it wasn't there"), "apt-key"); UNLINK_EXIT(EINTERNAL); } #undef UNLINK_EXIT @@ -229,14 +202,14 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, // check if it exit'ed normally … if (WIFEXITED(Status) == false) { - ioprintf(std::cerr, _("Sub-process %s exited unexpectedly"), "gpgv"); + ioprintf(std::cerr, _("Sub-process %s exited unexpectedly"), "apt-key"); exit(EINTERNAL); } // … and with a good exit code if (WEXITSTATUS(Status) != 0) { - ioprintf(std::cerr, _("Sub-process %s returned an error code (%u)"), "gpgv", WEXITSTATUS(Status)); + ioprintf(std::cerr, _("Sub-process %s returned an error code (%u)"), "apt-key", WEXITSTATUS(Status)); exit(WEXITSTATUS(Status)); } diff --git a/test/integration/framework b/test/integration/framework index 7cf4d8a6d..a9ba0014f 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -223,6 +223,7 @@ setupenvironment() { echo "Debug::NoLocking \"true\";" >> aptconfig.conf echo "APT::Get::Show-User-Simulation-Note \"false\";" >> aptconfig.conf echo "Dir::Bin::Methods \"${METHODSDIR}\";" >> aptconfig.conf + echo "Dir::Bin::apt-key \"${BUILDDIRECTORY}/apt-key\";" >> aptconfig.conf echo "Dir::Bin::dpkg \"fakeroot\";" >> aptconfig.conf echo "DPKG::options:: \"dpkg\";" >> aptconfig.conf echo "DPKG::options:: \"--root=${TMPWORKINGDIRECTORY}/rootdir\";" >> aptconfig.conf diff --git a/test/integration/test-apt-cdrom b/test/integration/test-apt-cdrom index 8d8fdf167..9fbc4288d 100755 --- a/test/integration/test-apt-cdrom +++ b/test/integration/test-apt-cdrom @@ -29,7 +29,7 @@ aptcdromlog() { test ! -e rootdir/media/cdrom || echo "CD-ROM is mounted, but shouldn't be!" test -e rootdir/media/cdrom-unmounted || echo "Unmounted CD-ROM doesn't exist, but it should!" aptcdrom "$@" -o quiet=1 >rootdir/tmp/apt-cdrom.log 2>&1 aptkey.list +testfileequal ./aptkey.list 'pub 1024R/F68C85A3 2013-12-19 +pub 2048R/DBAC8DAE 2010-08-18' # now try a different one # setup archive-keyring @@ -40,4 +43,6 @@ echo 'APT::Key::Net-Update-Enabled "1";' >> ./aptconfig.conf testequal "Checking for new archive signing keys now Key 'E8525D47528144E2' not added. It is not signed with a master key" aptkey --fakeroot net-update - +aptkey list | grep '^pub' > aptkey.list +testfileequal ./aptkey.list 'pub 1024R/F68C85A3 2013-12-19 +pub 2048R/DBAC8DAE 2010-08-18' diff --git a/test/integration/test-bug-733028-gpg-resource-limit b/test/integration/test-bug-733028-gpg-resource-limit new file mode 100755 index 000000000..f9c804963 --- /dev/null +++ b/test/integration/test-bug-733028-gpg-resource-limit @@ -0,0 +1,27 @@ +#!/bin/sh +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework +setupenvironment +configarchitecture 'i386' + +insertpackage 'unstable' 'foobar' 'all' '1' + +setupaptarchive --no-update + +for i in $(seq 1 50); do + touch rootdir/etc/apt/trusted.gpg.d/emptykey-${i}.gpg +done + +aptkey list | grep '^pub' > aptkey.list +testfileequal ./aptkey.list 'pub 2048R/DBAC8DAE 2010-08-18' + +msgtest 'Test for no gpg errors/warnings in' 'apt-get update' +aptget update > update.log 2>&1 +if grep -iq 'GPG' update.log; then + msgfail + cat update.log +else + msgpass +fi -- cgit v1.2.3-70-g09d2 From f1e1abd88a2a7f147c79b99956f88d37ab14e038 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 26 Jan 2014 19:23:58 +0100 Subject: use apt-key to wrap gpg calls in testcases beside testing apt-key a bit it also avoids duplicating gpghome setup code in apt-key and the test framework Git-Dch: Ignore --- test/integration/framework | 40 +++++++++------------------------------- 1 file changed, 9 insertions(+), 31 deletions(-) (limited to 'test/integration/framework') diff --git a/test/integration/framework b/test/integration/framework index a9ba0014f..1ab01b20a 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -133,13 +133,6 @@ gdb() { shift runapt command gdb --quiet -ex run "${BUILDDIRECTORY}/$CMD" --args "${BUILDDIRECTORY}/$CMD" "$@" } -gpg() { - # see apt-key for the whole trickery. Setup is done in setupenvironment - command gpg --ignore-time-conflict --no-options --no-default-keyring \ - --homedir "${TMPWORKINGDIRECTORY}/gnupghome" \ - --no-auto-check-trustdb --trust-model always \ - "$@" -} exitwithstatus() { # error if we about to overflow, but ... @@ -239,19 +232,6 @@ setupenvironment() { echo "Apt::Cmd::Disable-Script-Warning \"1\";" > rootdir/etc/apt/apt.conf.d/apt-binary configcompression '.' 'gz' #'bz2' 'lzma' 'xz' - # gpg needs a trustdb to function, but it can't be invalid (not even empty) - # see also apt-key where this trickery comes from: - local TRUSTDBDIR="${TMPWORKINGDIRECTORY}/gnupghome" - mkdir "$TRUSTDBDIR" - chmod 700 "$TRUSTDBDIR" - # We also don't use a secret keyring, of course, but gpg panics and - # implodes if there isn't one available - and writeable for imports - local SECRETKEYRING="${TRUSTDBDIR}/secring.gpg" - touch $SECRETKEYRING - # now create the trustdb with an (empty) dummy keyring - # newer gpg versions are fine without it, but play it safe for now - gpg --quiet --check-trustdb --secret-keyring $SECRETKEYRING --keyring $SECRETKEYRING >/dev/null 2>&1 - # cleanup the environment a bit # prefer our apt binaries over the system apt binaries export PATH="${BUILDDIRECTORY}:${PATH}:/usr/local/sbin:/usr/sbin:/sbin" @@ -449,8 +429,8 @@ Package: $NAME" >> ${BUILDDIR}/debian/control | while read SRC; do echo "pool/${SRC}" >> ${BUILDDIR}/../${RELEASE}.${DISTSECTION}.srclist # if expr match "${SRC}" '.*\.dsc' >/dev/null 2>&1; then -# gpg --yes --secret-keyring ./keys/joesixpack.sec \ -# --keyring ./keys/joesixpack.pub --default-key 'Joe Sixpack' \ +# aptkey --keyring ./keys/joesixpack.pub --quiet adv --yes \ +# --secret-keyring ./keys/joesixpack.sec --default-key 'Joe Sixpack' \ # --clearsign -o "${BUILDDIR}/../${SRC}.sign" "${BUILDDIR}/../$SRC" # mv "${BUILDDIR}/../${SRC}.sign" "${BUILDDIR}/../$SRC" # fi @@ -835,8 +815,9 @@ setupaptarchive() { signreleasefiles() { local SIGNER="${1:-Joe Sixpack}" - local GPG="gpg --batch --yes" - msgninfo "\tSign archive with $SIGNER key… " + local KEY="keys/$(echo "$SIGNER" | tr 'A-Z' 'a-z' | sed 's# ##g')" + local GPG="aptkey --quiet --keyring ${KEY}.pub adv --batch --yes --secret-keyring ${KEY}.sec" + msgninfo "\tSign archive with $SIGNER key $KEY… " local REXKEY='keys/rexexpired' local SECEXPIREBAK="${REXKEY}.sec.bak" local PUBEXPIREBAK="${REXKEY}.pub.bak" @@ -852,17 +833,14 @@ signreleasefiles() { cp $SECUNEXPIRED ${REXKEY}.sec cp $PUBUNEXPIRED ${REXKEY}.pub else - printf "expire\n1w\nsave\n" | $GPG --keyring ${REXKEY}.pub --secret-keyring ${REXKEY}.sec --command-fd 0 --edit-key "${SIGNER}" >/dev/null 2>&1 || true + if ! printf "expire\n1w\nsave\n" | $GPG --default-key "$SIGNER" --command-fd 0 --edit-key "${SIGNER}" >setexpire.gpg 2>&1; then + cat setexpire.gpg + exit 1 + fi cp ${REXKEY}.sec $SECUNEXPIRED cp ${REXKEY}.pub $PUBUNEXPIRED fi fi - for KEY in $(find keys/ -name '*.sec'); do - GPG="$GPG --secret-keyring $KEY" - done - for KEY in $(find keys/ -name '*.pub'); do - GPG="$GPG --keyring $KEY" - done for RELEASE in $(find aptarchive/ -name Release); do $GPG --default-key "$SIGNER" --armor --detach-sign --sign --output ${RELEASE}.gpg ${RELEASE} local INRELEASE="$(echo "${RELEASE}" | sed 's#/Release$#/InRelease#')" -- cgit v1.2.3-70-g09d2 From bd7fb5aa31f58917e8630f2981e78d190d465198 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Mon, 27 Jan 2014 18:26:44 +0100 Subject: add --secret-keyring option for apt-key For some advanced usecases it might be handy to specify the secret keyring to be used (e.g. as it is used in the testcases), but specifying it via a normal option for gnupg might not be available forever: http://lists.gnupg.org/pipermail/gnupg-users/2013-August/047180.html Git-Dch: Ignore --- cmdline/apt-key.in | 11 +++++++++++ test/integration/framework | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'test/integration/framework') diff --git a/cmdline/apt-key.in b/cmdline/apt-key.in index 74ca4d135..36824b6ec 100644 --- a/cmdline/apt-key.in +++ b/cmdline/apt-key.in @@ -287,6 +287,11 @@ while [ -n "$1" ]; do FORCED_KEYRING="$1" shift ;; + --secret-keyring) + shift + FORCED_SECRET_KEYRING="$1" + shift + ;; --fakeroot) requires_root() { true; } shift @@ -355,6 +360,12 @@ if [ "$command" != "help" ]; then GPG_CMD="$GPG_CMD --no-auto-check-trustdb --trust-model always" GPG="$GPG_CMD" + # for advanced operations, we might really need a secret keyring after all + if [ -n "$FORCED_SECRET_KEYRING" ] && [ -r "$FORCED_SECRET_KEYRING" ]; then + rm -f "$SECRETKEYRING" + cp -a "$FORCED_SECRET_KEYRING" "$SECRETKEYRING" + fi + # gpg defaults to mode 0600 for new keyrings. Create one with 0644 instead. if ! [ -e "$TRUSTEDFILE" ]; then if [ -w "$(dirname "$TRUSTEDFILE")" ]; then diff --git a/test/integration/framework b/test/integration/framework index 1ab01b20a..50f16fb46 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -429,8 +429,8 @@ Package: $NAME" >> ${BUILDDIR}/debian/control | while read SRC; do echo "pool/${SRC}" >> ${BUILDDIR}/../${RELEASE}.${DISTSECTION}.srclist # if expr match "${SRC}" '.*\.dsc' >/dev/null 2>&1; then -# aptkey --keyring ./keys/joesixpack.pub --quiet adv --yes \ -# --secret-keyring ./keys/joesixpack.sec --default-key 'Joe Sixpack' \ +# aptkey --keyring ./keys/joesixpack.pub --secret-keyring ./keys/joesixpack.sec --quiet \ +# adv --yes --default-key 'Joe Sixpack' \ # --clearsign -o "${BUILDDIR}/../${SRC}.sign" "${BUILDDIR}/../$SRC" # mv "${BUILDDIR}/../${SRC}.sign" "${BUILDDIR}/../$SRC" # fi @@ -816,7 +816,7 @@ setupaptarchive() { signreleasefiles() { local SIGNER="${1:-Joe Sixpack}" local KEY="keys/$(echo "$SIGNER" | tr 'A-Z' 'a-z' | sed 's# ##g')" - local GPG="aptkey --quiet --keyring ${KEY}.pub adv --batch --yes --secret-keyring ${KEY}.sec" + local GPG="aptkey --quiet --keyring ${KEY}.pub --secret-keyring ${KEY}.sec adv --batch --yes" msgninfo "\tSign archive with $SIGNER key $KEY… " local REXKEY='keys/rexexpired' local SECEXPIREBAK="${REXKEY}.sec.bak" -- cgit v1.2.3-70-g09d2 From 33a2267214eed2a11281c9f93b8cf10b4c436d94 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Thu, 6 Feb 2014 17:56:28 +0100 Subject: add --readonly option for apt-key adv Some advanced commands can be executed without the keyring being modified like --verify, so this adds an option to disable the mergeback and uses it for our gpg calling code. Git-Dch: Ignore --- apt-pkg/contrib/gpgv.cc | 1 + cmdline/apt-key.in | 9 ++++----- test/integration/framework | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'test/integration/framework') diff --git a/apt-pkg/contrib/gpgv.cc b/apt-pkg/contrib/gpgv.cc index 56e26ab99..cd17cd536 100644 --- a/apt-pkg/contrib/gpgv.cc +++ b/apt-pkg/contrib/gpgv.cc @@ -54,6 +54,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, Args.push_back(aptkey.c_str()); Args.push_back("--quiet"); + Args.push_back("--readonly"); Args.push_back("adv"); char statusfdstr[10]; diff --git a/cmdline/apt-key.in b/cmdline/apt-key.in index 9259fac0d..21d692631 100644 --- a/cmdline/apt-key.in +++ b/cmdline/apt-key.in @@ -337,20 +337,19 @@ while [ -n "$1" ]; do shift TRUSTEDFILE="$1" FORCED_KEYRING="$1" - shift ;; --secret-keyring) shift FORCED_SECRET_KEYRING="$1" - shift + ;; + --readonly) + merge_back_changes() { true; } ;; --fakeroot) requires_root() { true; } - shift ;; --quiet) aptkey_echo() { true; } - shift ;; --*) echo >&2 "Unknown option: $1" @@ -359,6 +358,7 @@ while [ -n "$1" ]; do *) break;; esac + shift done if [ -z "$TRUSTEDFILE" ]; then @@ -430,7 +430,6 @@ case "$command" in del|rm|remove) requires_root foreach_keyring_do 'remove_key_from_keyring' "$@" - merge_back_changes aptkey_echo "OK" ;; update) diff --git a/test/integration/framework b/test/integration/framework index 50f16fb46..fcdca34ce 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -429,7 +429,7 @@ Package: $NAME" >> ${BUILDDIR}/debian/control | while read SRC; do echo "pool/${SRC}" >> ${BUILDDIR}/../${RELEASE}.${DISTSECTION}.srclist # if expr match "${SRC}" '.*\.dsc' >/dev/null 2>&1; then -# aptkey --keyring ./keys/joesixpack.pub --secret-keyring ./keys/joesixpack.sec --quiet \ +# aptkey --keyring ./keys/joesixpack.pub --secret-keyring ./keys/joesixpack.sec --quiet --readonly \ # adv --yes --default-key 'Joe Sixpack' \ # --clearsign -o "${BUILDDIR}/../${SRC}.sign" "${BUILDDIR}/../$SRC" # mv "${BUILDDIR}/../${SRC}.sign" "${BUILDDIR}/../$SRC" @@ -816,7 +816,7 @@ setupaptarchive() { signreleasefiles() { local SIGNER="${1:-Joe Sixpack}" local KEY="keys/$(echo "$SIGNER" | tr 'A-Z' 'a-z' | sed 's# ##g')" - local GPG="aptkey --quiet --keyring ${KEY}.pub --secret-keyring ${KEY}.sec adv --batch --yes" + local GPG="aptkey --quiet --keyring ${KEY}.pub --secret-keyring ${KEY}.sec --readonly adv --batch --yes" msgninfo "\tSign archive with $SIGNER key $KEY… " local REXKEY='keys/rexexpired' local SECEXPIREBAK="${REXKEY}.sec.bak" -- cgit v1.2.3-70-g09d2