chiark / gitweb /
index: ensure index.xml timestamp is in UTC, closes #481
[fdroidserver.git] / tests / run-tests
index f7acd069fc0ad271f3bf46656871e5f041bfe088..9ab5a9b6f714b3cf9a545a0c1d94c08f11df8f12 100755 (executable)
@@ -8,14 +8,14 @@ echo_header() {
 
 copy_apks_into_repo() {
     set +x
-    for f in `find $APKDIR -name '*.apk' | grep -F -v -e unaligned -e unsigned -e badsig -e badcert`; do
-        name=$(basename $(dirname `dirname $f`))
+    find $APKDIR -type f -name '*.apk' -print0 | while IFS= read -r -d '' f; do
+        echo $f | grep -F -v -e unaligned -e unsigned -e badsig -e badcert -e bad-unicode -e janus.apk || continue
         apk=`$aapt dump badging "$f" | sed -n "s,^package: name='\(.*\)' versionCode='\([0-9][0-9]*\)' .*,\1_\2.apk,p"`
-        test $f -nt repo/$apk && rm -f repo/$apk  # delete existing if $f is newer
+        test "$f" -nt repo/$apk && rm -f repo/$apk  # delete existing if $f is newer
         if [ ! -e repo/$apk ] && [ ! -e archive/$apk ]; then
             echo "$f --> repo/$apk"
-            ln $f $1/repo/$apk || \
-                rsync -axv $f $1/repo/$apk # rsync if hard link is not possible
+            ln "$f" $1/repo/$apk || \
+                rsync -axv "$f" $1/repo/$apk # rsync if hard link is not possible
         fi
     done
     set -x
@@ -33,7 +33,7 @@ create_fake_android_home() {
 
 create_test_dir() {
     test -e $WORKSPACE/.testfiles || mkdir $WORKSPACE/.testfiles
-    TMPDIR=$WORKSPACE/.testfiles  mktemp -d
+    mktemp -d $WORKSPACE/.testfiles/run-tests.XXXX
 }
 
 create_test_file() {
@@ -41,6 +41,27 @@ create_test_file() {
     TMPDIR=$WORKSPACE/.testfiles  mktemp
 }
 
+fdroid_init_with_prebuilt_keystore() {
+    if [ -z "$1" ]; then
+        keystore=$WORKSPACE/tests/keystore.jks
+    else
+        keystore="$1"
+    fi
+    $fdroid init --keystore $keystore --repo-keyalias=sova
+    echo 'keystorepass = "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI="' >> config.py
+    echo 'keypass = "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI="' >> config.py
+}
+
+# the < is reverse since 0 means success in exit codes
+have_git_2_3() {
+    python3 -c "import sys; from distutils.version import LooseVersion as V; sys.exit(V(sys.argv[3]) < V('2.3'))" `git --version`
+}
+
+is_MD5_disabled() {
+    javac $WORKSPACE/tests/IsMD5Disabled.java && java -cp $WORKSPACE/tests IsMD5Disabled
+    return $?
+}
+
 #------------------------------------------------------------------------------#
 # "main"
 
@@ -81,9 +102,11 @@ if [ -z $aapt ]; then
     aapt=`ls -1 $ANDROID_HOME/build-tools/*/aapt | sort | tail -1`
 fi
 
-# allow the location of python to be overridden
-if [ -z $python ]; then
-    python=python2
+# try to use GNU sed on OSX/BSD cuz BSD sed sucks
+if which gsed; then
+    sed=gsed
+else
+    sed=sed
 fi
 
 set -x # show each command as it is executed
@@ -100,7 +123,13 @@ echo_header "test python getsig replacement"
 
 cd $WORKSPACE/tests/getsig
 ./make.sh
-for testcase in $WORKSPACE/tests/*.TestCase; do
+
+cd $WORKSPACE/tests
+for testcase in $WORKSPACE/tests/i*.TestCase; do
+    if [ $testcase == $WORKSPACE/tests/install.TestCase ]; then
+        echo "skipping install.TestCase, its too troublesome in CI builds"
+        continue
+    fi
     $testcase
 done
 
@@ -112,14 +141,397 @@ $fdroid --version
 
 
 #------------------------------------------------------------------------------#
-echo_header "build the TeX manual"
+echo_header 'run process when building and signing are on separate machines'
+
+REPOROOT=`create_test_dir`
+cd $REPOROOT
+cp $WORKSPACE/tests/keystore.jks $REPOROOT/
+$fdroid init --keystore keystore.jks --repo-keyalias=sova
+echo 'keystorepass = "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI="' >> config.py
+echo 'keypass = "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI="' >> config.py
+echo "accepted_formats = ['txt', 'yml']" >> config.py
+echo 'keydname = "CN=Birdman, OU=Cell, O=Alcatraz, L=Alcatraz, S=California, C=US"' >> config.py
+test -d archive || mkdir archive
+test -d metadata || mkdir metadata
+cp $WORKSPACE/tests/metadata/info.guardianproject.urzip.yml metadata/
+test -d repo || mkdir repo
+test -d unsigned || mkdir unsigned
+cp $WORKSPACE/tests/urzip-release-unsigned.apk unsigned/info.guardianproject.urzip_100.apk
+$fdroid publish --verbose
+$fdroid update --verbose --nosign
+$fdroid signindex --verbose
+test -e repo/index.xml
+test -e repo/index.jar
+test -e repo/index-v1.jar
+test -e tmp/apkcache
+! test -z tmp/apkcache
+test -L urzip.apk
+grep -F '<application id=' repo/index.xml > /dev/null
+
+
+#------------------------------------------------------------------------------#
+echo_header "test UTF-8 metadata"
+
+REPOROOT=`create_test_dir`
+cd $REPOROOT
+
+fdroid_init_with_prebuilt_keystore
+$sed -i.tmp 's,^ *repo_description.*,repo_description = """获取已安装在您的设备上的应用的,' config.py
+echo "mirrors = ('https://foo.bar/fdroid', 'http://secret.onion/fdroid')" >> config.py
+mkdir metadata
+cp $WORKSPACE/tests/urzip.apk $WORKSPACE/tests/bad-unicode*.apk repo/
+cp $WORKSPACE/tests/metadata/info.guardianproject.urzip.yml metadata/
+
+$fdroid readmeta
+$fdroid update
 
-cd $WORKSPACE/docs
-# this is only ever generated officially on GNU/Linux
-if [ `uname -s` == "Linux" ]; then
-    ./gendocs.sh -o html --email admin@f-droid.org fdroid "F-Droid Server Manual"
+
+#------------------------------------------------------------------------------#
+echo_header 'run "fdroid build" in fresh git checkout from import.TestCase'
+
+cd $WORKSPACE/tests/tmp/importer
+git remote update -p
+git clean -fdx
+# stick with known working commit, in case future commits break things for this code
+git reset --hard fea54e1161d5eb9eb1a54e26253ef84d3ab63705
+if [ -d $ANDROID_HOME/platforms/android-23 && -d $ANDROID_HOME/build-tools/23.0.3 ]; then
+    echo "build_tools = '`ls -1 $ANDROID_HOME/build-tools/ | sort -n | tail -1`'" > config.py
+    echo "force_build_tools = True" >> config.py
+    $fdroid build --verbose org.fdroid.ci.test.app:300
+else
+    echo 'WARNING: Skipping "fdroid build" test since android-23 is missing!'
 fi
 
+#------------------------------------------------------------------------------#
+echo_header 'copy git import and run "fdroid scanner" on it'
+
+REPOROOT=`create_test_dir`
+cd $REPOROOT
+cp $WORKSPACE/examples/fdroid-icon.png $REPOROOT/
+mkdir metadata
+echo "Auto Name:Just A Test" > metadata/org.fdroid.ci.test.app.txt
+echo "Web Site:" >> metadata/org.fdroid.ci.test.app.txt
+echo "Build:0.3,300" >> metadata/org.fdroid.ci.test.app.txt
+echo "    commit=0.3" >> metadata/org.fdroid.ci.test.app.txt
+echo "    subdir=app" >> metadata/org.fdroid.ci.test.app.txt
+echo "    gradle=yes" >> metadata/org.fdroid.ci.test.app.txt
+echo "" >> metadata/org.fdroid.ci.test.app.txt
+echo "Repo:https://gitlab.com/fdroid/ci-test-app.git" >> metadata/org.fdroid.ci.test.app.txt
+echo "Repo Type:git" >> metadata/org.fdroid.ci.test.app.txt
+mkdir build
+cp -a $WORKSPACE/tests/tmp/importer build/org.fdroid.ci.test.app
+ls -l build/org.fdroid.ci.test.app
+$fdroid scanner org.fdroid.ci.test.app --verbose
+
+
+#------------------------------------------------------------------------------#
+echo_header "copy tests/repo, generate java/gpg keys, update, and gpgsign"
+
+REPOROOT=`create_test_dir`
+GNUPGHOME=$REPOROOT/gnupghome
+cd $REPOROOT
+fdroid_init_with_prebuilt_keystore
+cp -a $WORKSPACE/tests/metadata $WORKSPACE/tests/repo $WORKSPACE/tests/stats $REPOROOT/
+cp -a $WORKSPACE/tests/gnupghome $GNUPGHOME
+chmod 0700 $GNUPGHOME
+echo "accepted_formats = ['json', 'txt', 'yml']" >> config.py
+echo "install_list = 'org.adaway'" >> config.py
+echo "uninstall_list = ('com.android.vending', 'com.facebook.orca',)" >> config.py
+echo "gpghome = '$GNUPGHOME'" >> config.py
+echo "gpgkey = 'CE71F7FB'" >> config.py
+echo "mirrors = ('http://foobarfoobarfoobar.onion/fdroid','https://foo.bar/fdroid',)" >> config.py
+$fdroid update --verbose --pretty
+test -e repo/index.xml
+test -e repo/index.jar
+test -e repo/index-v1.jar
+grep -F '<application id=' repo/index.xml > /dev/null
+grep -F '<install packageName=' repo/index.xml > /dev/null
+grep -F '<uninstall packageName=' repo/index.xml > /dev/null
+# OSX tests are run on Travis-CI, and gpg fails to launch gpg-agent there
+if [ "$TRAVIS_OS_NAME" != "osx" ]; then
+    $fdroid gpgsign --verbose
+    $fdroid gpgsign --verbose
+    test -e repo/obb.mainpatch.current_1619.apk.asc
+    test -e repo/obb.main.twoversions_1101617_src.tar.gz.asc
+    ! test -e repo/obb.mainpatch.current_1619.apk.asc.asc
+    ! test -e repo/obb.main.twoversions_1101617_src.tar.gz.asc.asc
+    ! test -e repo/index.xml.asc
+fi
+
+v0timestamp=`$sed -n -e 's,.*timestamp="\([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\)".*,\1,p' repo/index.xml`
+v1timestamp=`$sed -n -e 's,.*"timestamp": \([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\).*,\1,p' repo/index-v1.json`
+test $v0timestamp -eq $v1timestamp
+
+# we can't easily reproduce the timestamps for things, so just hardcode them
+$sed -i.tmp -e 's,timestamp="[0-9]*",timestamp="1480431575",' repo/index.xml
+diff -uw $WORKSPACE/tests/repo/index.xml repo/index.xml
+sed -i --expression='s,"timestamp": [0-9]*,"timestamp": 1502845383782,' repo/index-v1.json
+diff -uw $WORKSPACE/tests/repo/index-v1.json repo/index-v1.json
+
+
+#------------------------------------------------------------------------------#
+echo_header 'test moving lots of APKs to the archive'
+
+REPOROOT=`create_test_dir`
+cd $REPOROOT
+fdroid_init_with_prebuilt_keystore
+echo "accepted_formats = ['txt']" >> config.py
+$sed -i.tmp '/allow_disabled_algorithms/d' config.py
+test -d metadata || mkdir metadata
+cp $WORKSPACE/tests/metadata/*.txt metadata/
+echo 'Summary:good test version of urzip' > metadata/info.guardianproject.urzip.txt
+echo 'Summary:good MD5 sig, which is disabled algorithm' > metadata/org.bitbucket.tickytacky.mirrormirror.txt
+$sed -i.tmp '/Archive Policy:/d' metadata/*.txt
+test -d repo || mkdir repo
+cp $WORKSPACE/tests/urzip.apk \
+   $WORKSPACE/tests/org.bitbucket.tickytacky.mirrormirror_[0-9].apk \
+   $WORKSPACE/tests/repo/com.politedroid_[0-9].apk \
+   $WORKSPACE/tests/repo/obb.main.twoversions_110161[357].apk \
+   repo/
+$sed -i.tmp 's,archive_older = [0-9],archive_older = 3,' config.py
+
+$fdroid update --pretty --nosign
+echo "This will fail when jarsigner allows MD5 for APK signatures"
+test `grep '<package>' archive/index.xml | wc -l` -eq 5
+test `grep '<package>' repo/index.xml | wc -l` -eq 7
+
+
+#------------------------------------------------------------------------------#
+echo_header 'test per-app "Archive Policy"'
+
+REPOROOT=`create_test_dir`
+cd $REPOROOT
+fdroid_init_with_prebuilt_keystore
+echo "accepted_formats = ['txt']" >> config.py
+test -d metadata || mkdir metadata
+cp $WORKSPACE/tests/metadata/com.politedroid.txt metadata/
+test -d repo || mkdir repo
+cp $WORKSPACE/tests/repo/com.politedroid_[0-9].apk repo/
+$sed -i.tmp 's,archive_older = [0-9],archive_older = 3,' config.py
+
+$fdroid update --pretty --nosign
+test `grep '<package>' archive/index.xml | wc -l` -eq 0
+test `grep '<package>' repo/index.xml | wc -l` -eq 4
+grep -F com.politedroid_3.apk repo/index.xml
+grep -F com.politedroid_4.apk repo/index.xml
+grep -F com.politedroid_5.apk repo/index.xml
+grep -F com.politedroid_6.apk repo/index.xml
+test -e repo/com.politedroid_3.apk
+test -e repo/com.politedroid_4.apk
+test -e repo/com.politedroid_5.apk
+test -e repo/com.politedroid_6.apk
+
+echo "enable one app in the repo"
+$sed -i.tmp 's,^Archive Policy:4,Archive Policy:1,' metadata/com.politedroid.txt
+$fdroid update --pretty --nosign
+test `grep '<package>' archive/index.xml | wc -l` -eq 3
+test `grep '<package>' repo/index.xml | wc -l` -eq 1
+grep -F com.politedroid_3.apk archive/index.xml
+grep -F com.politedroid_4.apk archive/index.xml
+grep -F com.politedroid_5.apk archive/index.xml
+grep -F com.politedroid_6.apk repo/index.xml
+test -e archive/com.politedroid_3.apk
+test -e archive/com.politedroid_4.apk
+test -e archive/com.politedroid_5.apk
+test -e repo/com.politedroid_6.apk
+
+echo "remove all apps from the repo"
+$sed -i.tmp 's,^Archive Policy:1,Archive Policy:0,' metadata/com.politedroid.txt
+$fdroid update --pretty --nosign
+test `grep '<package>' archive/index.xml | wc -l` -eq 4
+test `grep '<package>' repo/index.xml | wc -l` -eq 0
+grep -F com.politedroid_3.apk archive/index.xml
+grep -F com.politedroid_4.apk archive/index.xml
+grep -F com.politedroid_5.apk archive/index.xml
+grep -F com.politedroid_6.apk archive/index.xml
+test -e archive/com.politedroid_3.apk
+test -e archive/com.politedroid_4.apk
+test -e archive/com.politedroid_5.apk
+test -e archive/com.politedroid_6.apk
+! test -e repo/com.politedroid_6.apk
+
+echo "move back one from archive to the repo"
+$sed -i.tmp 's,^Archive Policy:0,Archive Policy:1,' metadata/com.politedroid.txt
+$fdroid update --pretty --nosign
+test `grep '<package>' archive/index.xml | wc -l` -eq 3
+test `grep '<package>' repo/index.xml | wc -l` -eq 1
+grep -F com.politedroid_3.apk archive/index.xml
+grep -F com.politedroid_4.apk archive/index.xml
+grep -F com.politedroid_5.apk archive/index.xml
+grep -F com.politedroid_6.apk repo/index.xml
+test -e archive/com.politedroid_3.apk
+test -e archive/com.politedroid_4.apk
+test -e archive/com.politedroid_5.apk
+! test -e archive/com.politedroid_6.apk
+test -e repo/com.politedroid_6.apk
+
+
+
+#------------------------------------------------------------------------------#
+echo_header 'test moving old APKs to and from the archive'
+
+REPOROOT=`create_test_dir`
+cd $REPOROOT
+fdroid_init_with_prebuilt_keystore
+echo "accepted_formats = ['txt']" >> config.py
+test -d metadata || mkdir metadata
+cp $WORKSPACE/tests/metadata/com.politedroid.txt metadata/
+$sed -i.tmp '/Archive Policy:/d' metadata/com.politedroid.txt
+test -d repo || mkdir repo
+cp $WORKSPACE/tests/repo/com.politedroid_[0-9].apk repo/
+$sed -i.tmp 's,archive_older = [0-9],archive_older = 3,' config.py
+
+$fdroid update --pretty --nosign
+test `grep '<package>' archive/index.xml | wc -l` -eq 1
+test `grep '<package>' repo/index.xml | wc -l` -eq 3
+grep -F com.politedroid_3.apk archive/index.xml
+grep -F com.politedroid_4.apk repo/index.xml
+grep -F com.politedroid_5.apk repo/index.xml
+grep -F com.politedroid_6.apk repo/index.xml
+test -e archive/com.politedroid_3.apk
+test -e repo/com.politedroid_4.apk
+test -e repo/com.politedroid_5.apk
+test -e repo/com.politedroid_6.apk
+
+$sed -i.tmp 's,archive_older = 3,archive_older = 1,' config.py
+$fdroid update --pretty --nosign
+test `grep '<package>' archive/index.xml | wc -l` -eq 3
+test `grep '<package>' repo/index.xml | wc -l` -eq 1
+grep -F com.politedroid_3.apk archive/index.xml
+grep -F com.politedroid_4.apk archive/index.xml
+grep -F com.politedroid_5.apk archive/index.xml
+grep -F com.politedroid_6.apk repo/index.xml
+test -e archive/com.politedroid_3.apk
+test -e archive/com.politedroid_4.apk
+test -e archive/com.politedroid_5.apk
+test -e repo/com.politedroid_6.apk
+
+# disabling deletes from the archive
+$sed -i.tmp 's/Build:1.3,4/Build:1.3,4\n    disable=testing deletion/' metadata/com.politedroid.txt
+$fdroid update --pretty --nosign
+test `grep '<package>' archive/index.xml | wc -l` -eq 2
+test `grep '<package>' repo/index.xml | wc -l` -eq 1
+grep -F com.politedroid_3.apk archive/index.xml
+! grep -F com.politedroid_4.apk archive/index.xml
+grep -F com.politedroid_5.apk archive/index.xml
+grep -F com.politedroid_6.apk repo/index.xml
+test -e archive/com.politedroid_3.apk
+! test -e archive/com.politedroid_4.apk
+test -e archive/com.politedroid_5.apk
+test -e repo/com.politedroid_6.apk
+
+# disabling deletes from the repo, and promotes one from the archive
+$sed -i.tmp 's/Build:1.5,6/Build:1.5,6\n    disable=testing deletion/' metadata/com.politedroid.txt
+$fdroid update --pretty --nosign
+test `grep '<package>' archive/index.xml | wc -l` -eq 1
+test `grep '<package>' repo/index.xml | wc -l` -eq 1
+grep -F com.politedroid_3.apk archive/index.xml
+grep -F com.politedroid_5.apk repo/index.xml
+! grep -F com.politedroid_6.apk repo/index.xml
+test -e archive/com.politedroid_3.apk
+test -e repo/com.politedroid_5.apk
+! test -e repo/com.politedroid_6.apk
+
+
+#------------------------------------------------------------------------------#
+echo_header 'test allowing disabled signatures in repo and archive'
+
+REPOROOT=`create_test_dir`
+cd $REPOROOT
+fdroid_init_with_prebuilt_keystore
+echo "accepted_formats = ['txt']" >> config.py
+echo 'allow_disabled_algorithms = True' >> config.py
+$sed -i.tmp 's,archive_older = [0-9],archive_older = 3,' config.py
+test -d metadata || mkdir metadata
+cp $WORKSPACE/tests/metadata/com.politedroid.txt metadata/
+echo 'Summary:good test version of urzip' > metadata/info.guardianproject.urzip.txt
+echo 'Summary:good MD5 sig, disabled algorithm' > metadata/org.bitbucket.tickytacky.mirrormirror.txt
+$sed -i.tmp '/Archive Policy:/d' metadata/*.txt
+test -d repo || mkdir repo
+cp $WORKSPACE/tests/repo/com.politedroid_[0-9].apk \
+   $WORKSPACE/tests/org.bitbucket.tickytacky.mirrormirror_[0-9].apk \
+   $WORKSPACE/tests/urzip-badsig.apk \
+   repo/
+
+$fdroid update --pretty --nosign
+test `grep '<package>' archive/index.xml | wc -l` -eq 2
+test `grep '<package>' repo/index.xml | wc -l` -eq 6
+grep -F com.politedroid_3.apk archive/index.xml
+grep -F com.politedroid_4.apk repo/index.xml
+grep -F com.politedroid_5.apk repo/index.xml
+grep -F com.politedroid_6.apk repo/index.xml
+grep -F org.bitbucket.tickytacky.mirrormirror_1.apk archive/index.xml
+grep -F org.bitbucket.tickytacky.mirrormirror_2.apk repo/index.xml
+grep -F org.bitbucket.tickytacky.mirrormirror_3.apk repo/index.xml
+grep -F org.bitbucket.tickytacky.mirrormirror_4.apk repo/index.xml
+! grep -F urzip-badsig.apk repo/index.xml
+! grep -F urzip-badsig.apk archive/index.xml
+test -e archive/com.politedroid_3.apk
+test -e repo/com.politedroid_4.apk
+test -e repo/com.politedroid_5.apk
+test -e repo/com.politedroid_6.apk
+test -e archive/org.bitbucket.tickytacky.mirrormirror_1.apk
+test -e repo/org.bitbucket.tickytacky.mirrormirror_2.apk
+test -e repo/org.bitbucket.tickytacky.mirrormirror_3.apk
+test -e repo/org.bitbucket.tickytacky.mirrormirror_4.apk
+test -e archive/urzip-badsig.apk
+
+$sed -i.tmp '/allow_disabled_algorithms/d' config.py
+$fdroid update --pretty --nosign
+test `grep '<package>' archive/index.xml | wc -l` -eq 5
+test `grep '<package>' repo/index.xml | wc -l` -eq 3
+grep -F org.bitbucket.tickytacky.mirrormirror_1.apk archive/index.xml
+grep -F org.bitbucket.tickytacky.mirrormirror_2.apk archive/index.xml
+grep -F org.bitbucket.tickytacky.mirrormirror_3.apk archive/index.xml
+grep -F org.bitbucket.tickytacky.mirrormirror_4.apk archive/index.xml
+grep -F com.politedroid_3.apk archive/index.xml
+grep -F com.politedroid_4.apk repo/index.xml
+grep -F com.politedroid_5.apk repo/index.xml
+grep -F com.politedroid_6.apk repo/index.xml
+! grep -F urzip-badsig.apk repo/index.xml
+! grep -F urzip-badsig.apk archive/index.xml
+test -e archive/org.bitbucket.tickytacky.mirrormirror_1.apk
+test -e archive/org.bitbucket.tickytacky.mirrormirror_2.apk
+test -e archive/org.bitbucket.tickytacky.mirrormirror_3.apk
+test -e archive/org.bitbucket.tickytacky.mirrormirror_4.apk
+test -e archive/com.politedroid_3.apk
+test -e archive/urzip-badsig.apk
+test -e repo/com.politedroid_4.apk
+test -e repo/com.politedroid_5.apk
+test -e repo/com.politedroid_6.apk
+
+
+#------------------------------------------------------------------------------#
+echo_header 'rename apks with `fdroid update --rename-apks`, --nosign for speed'
+
+REPOROOT=`create_test_dir`
+cd $REPOROOT
+fdroid_init_with_prebuilt_keystore
+echo "accepted_formats = ['txt', 'yml']" >> config.py
+echo 'keydname = "CN=Birdman, OU=Cell, O=Alcatraz, L=Alcatraz, S=California, C=US"' >> config.py
+test -d metadata || mkdir metadata
+cp $WORKSPACE/tests/metadata/info.guardianproject.urzip.yml metadata/
+test -d repo || mkdir repo
+cp $WORKSPACE/tests/urzip.apk "repo/asdfiuhk urzip-πÇÇπÇÇ现代汉语通用字-български-عربي1234 ö.apk"
+$fdroid update --rename-apks --pretty --nosign
+test -e repo/info.guardianproject.urzip_100.apk
+grep -F 'info.guardianproject.urzip_100.apk' repo/index-v1.json repo/index.xml
+cp $WORKSPACE/tests/urzip-release.apk repo/
+$fdroid update --rename-apks --pretty --nosign
+test -e repo/info.guardianproject.urzip_100.apk
+test -e repo/info.guardianproject.urzip_100_b4964fd.apk
+grep -F 'info.guardianproject.urzip_100.apk' repo/index-v1.json repo/index.xml
+grep -F 'info.guardianproject.urzip_100_b4964fd.apk' repo/index-v1.json
+! grep -F 'info.guardianproject.urzip_100_b4964fd.apk' repo/index.xml
+cp $WORKSPACE/tests/urzip-release.apk repo/
+$fdroid update --rename-apks --pretty --nosign
+test -e repo/info.guardianproject.urzip_100.apk
+test -e repo/info.guardianproject.urzip_100_b4964fd.apk
+test -e duplicates/repo/info.guardianproject.urzip_100_b4964fd.apk
+grep -F 'info.guardianproject.urzip_100.apk' repo/index-v1.json repo/index.xml
+grep -F 'info.guardianproject.urzip_100_b4964fd.apk' repo/index-v1.json
+! grep -F 'info.guardianproject.urzip_100_b4964fd.apk' repo/index.xml
+
 
 #------------------------------------------------------------------------------#
 echo_header "test metadata checks"
@@ -127,7 +539,6 @@ echo_header "test metadata checks"
 REPOROOT=`create_test_dir`
 cd $REPOROOT
 
-touch config.py
 mkdir repo
 cp $WORKSPACE/tests/urzip.apk $REPOROOT/repo/
 
@@ -146,7 +557,7 @@ cp $WORKSPACE/tests/metadata/org.smssecure.smssecure.txt $REPOROOT/metadata/
 $fdroid readmeta
 
 # now make a fake duplicate
-touch $REPOROOT/metadata/org.smssecure.smssecure.yaml
+touch $REPOROOT/metadata/org.smssecure.smssecure.yml
 
 set +e
 $fdroid readmeta
@@ -166,7 +577,7 @@ REPOROOT=`create_test_dir`
 cd $REPOROOT
 mkdir repo
 mkdir metadata
-echo "License:GPL" >> metadata/fake.txt
+echo "License:GPL-2.0" >> metadata/fake.txt
 echo "Summary:Yup still fake" >> metadata/fake.txt
 echo "Categories:Internet" >> metadata/fake.txt
 echo "Description:" >> metadata/fake.txt
@@ -180,7 +591,7 @@ LOCAL_COPY_DIR=`create_test_dir`/fdroid
 mkdir -p $LOCAL_COPY_DIR/repo
 echo "local_copy_dir = '$LOCAL_COPY_DIR'" >> config.py
 
-$fdroid checkupdates
+$fdroid checkupdates --allow-dirty
 $fdroid gpgsign
 $fdroid lint
 $fdroid readmeta
@@ -195,10 +606,10 @@ $fdroid install || true
 
 
 #------------------------------------------------------------------------------#
-echo_header "create a source tarball and use that to build a repo"
+echo_header "create a source tarball"
 
 cd $WORKSPACE
-$python setup.py sdist
+./setup.py compile_catalog sdist
 
 REPOROOT=`create_test_dir`
 cd $REPOROOT
@@ -250,7 +661,7 @@ echo_header "setup a new repo from scratch using ANDROID_HOME and do a local syn
 
 REPOROOT=`create_test_dir`
 cd $REPOROOT
-$fdroid init
+fdroid_init_with_prebuilt_keystore
 copy_apks_into_repo $REPOROOT
 $fdroid update --create-metadata --verbose
 $fdroid readmeta
@@ -260,8 +671,9 @@ LOCALCOPYDIR=`create_test_dir`/fdroid
 $fdroid server update --local-copy-dir=$LOCALCOPYDIR
 NEWREPOROOT=`create_test_dir`
 cd $NEWREPOROOT
-$fdroid init
-$fdroid server update --local-copy-dir=$LOCALCOPYDIR --sync-from-local-copy-dir
+fdroid_init_with_prebuilt_keystore
+echo "sync_from_local_copy_dir = True" >> config.py
+$fdroid server update --local-copy-dir=$LOCALCOPYDIR
 
 
 #------------------------------------------------------------------------------#
@@ -361,9 +773,32 @@ $fdroid readmeta
 grep -F '<application id=' repo/index.xml > /dev/null
 test -e repo/index.xml
 test -e repo/index.jar
+test -e repo/index-v1.jar
+test -e tmp/apkcache
+! test -z tmp/apkcache
 export ANDROID_HOME=$STORED_ANDROID_HOME
 
 
+#------------------------------------------------------------------------------#
+echo_header "check duplicate files are properly handled by fdroid update"
+
+REPOROOT=`create_test_dir`
+cd $REPOROOT
+fdroid_init_with_prebuilt_keystore
+mkdir $REPOROOT/metadata
+cp -a $WORKSPACE/tests/metadata/obb.mainpatch.current.txt $REPOROOT/metadata
+echo "accepted_formats = ['txt']" >> config.py
+cp $WORKSPACE/tests/repo/obb.mainpatch.current_1619.apk $REPOROOT/repo/
+cp $WORKSPACE/tests/repo/obb.mainpatch.current_1619_another-release-key.apk $REPOROOT/repo/
+$fdroid update --pretty
+grep -F 'obb.mainpatch.current_1619.apk' repo/index.xml repo/index-v1.json
+grep -F 'obb.mainpatch.current_1619_another-release-key.apk' repo/index-v1.json
+! grep -F 'obb.mainpatch.current_1619_another-release-key.apk' repo/index.xml
+# die if there are exact duplicates
+cp $WORKSPACE/tests/repo/obb.mainpatch.current_1619.apk $REPOROOT/repo/duplicate.apk
+! $fdroid update
+
+
 #------------------------------------------------------------------------------#
 echo_header "setup new repo from scratch using ANDROID_HOME, putting APKs in repo first"
 
@@ -371,7 +806,7 @@ REPOROOT=`create_test_dir`
 cd $REPOROOT
 mkdir repo
 copy_apks_into_repo $REPOROOT
-$fdroid init
+fdroid_init_with_prebuilt_keystore
 $fdroid update --create-metadata --verbose
 $fdroid readmeta
 grep -F '<application id=' repo/index.xml > /dev/null
@@ -390,6 +825,9 @@ $fdroid update --create-metadata --verbose
 $fdroid readmeta
 test -e repo/index.xml
 test -e repo/index.jar
+test -e repo/index-v1.jar
+test -e tmp/apkcache
+! test -z tmp/apkcache
 grep -F '<application id=' repo/index.xml > /dev/null
 
 
@@ -399,7 +837,6 @@ echo_header "setup a new repo manually and generate a keystore"
 REPOROOT=`create_test_dir`
 KEYSTORE=$REPOROOT/keystore.jks
 cd $REPOROOT
-touch config.py
 cp $WORKSPACE/examples/fdroid-icon.png $REPOROOT/
 ! test -e $KEYSTORE
 set +e
@@ -418,6 +855,9 @@ $fdroid update --create-metadata --verbose
 $fdroid readmeta
 test -e repo/index.xml
 test -e repo/index.jar
+test -e repo/index-v1.jar
+test -e tmp/apkcache
+! test -z tmp/apkcache
 grep -F '<application id=' repo/index.xml > /dev/null
 
 
@@ -434,6 +874,7 @@ $fdroid update --create-metadata --verbose
 $fdroid readmeta
 test -e repo/index.xml
 test -e repo/index.jar
+test -e repo/index-v1.jar
 grep -F '<application id=' repo/index.xml > /dev/null
 test -e $REPOROOT/repo/info.guardianproject.urzip_100.apk || \
     cp $WORKSPACE/tests/urzip.apk $REPOROOT/repo/
@@ -441,6 +882,9 @@ $fdroid update --create-metadata --verbose
 $fdroid readmeta
 test -e repo/index.xml
 test -e repo/index.jar
+test -e repo/index-v1.jar
+test -e tmp/apkcache
+! test -z tmp/apkcache
 grep -F '<application id=' repo/index.xml > /dev/null
 
 
@@ -459,7 +903,6 @@ echo_header "setup a new repo with no keystore, add APK, and update"
 REPOROOT=`create_test_dir`
 KEYSTORE=$REPOROOT/keystore.jks
 cd $REPOROOT
-touch config.py
 touch fdroid-icon.png
 mkdir repo
 cp $WORKSPACE/tests/urzip.apk $REPOROOT/repo/
@@ -490,23 +933,54 @@ fi
 set -e
 
 
+#------------------------------------------------------------------------------#
+echo_header "copy tests/repo, update with binary transparency log"
+
+REPOROOT=`create_test_dir`
+GIT_REMOTE=`create_test_dir`
+GNUPGHOME=$REPOROOT/gnupghome
+cd $REPOROOT
+fdroid_init_with_prebuilt_keystore
+cp -a $WORKSPACE/tests/metadata $WORKSPACE/tests/repo $WORKSPACE/tests/stats $REPOROOT/
+echo "binary_transparency_remote = '$GIT_REMOTE'" >> config.py
+echo "accepted_formats = ['json', 'txt', 'yml']" >> config.py
+$fdroid update --verbose
+if have_git_2_3; then
+    $fdroid server update --verbose
+    test -e repo/index.xml
+    test -e repo/index.jar
+    test -e repo/index-v1.jar
+    grep -F '<application id=' repo/index.xml > /dev/null
+    cd binary_transparency
+    [ `git rev-list --count HEAD` == "2" ]
+    cd $GIT_REMOTE
+    [ `git rev-list --count HEAD` == "2" ]
+else
+    echo "Skipping test, `git --version` older than 2.3"
+fi
+
+
 #------------------------------------------------------------------------------#
 echo_header "setup a new repo with keystore with APK, update, then without key"
 
 REPOROOT=`create_test_dir`
 KEYSTORE=$REPOROOT/keystore.jks
 cd $REPOROOT
-$fdroid init --keystore $KEYSTORE
+cp $WORKSPACE/tests/keystore.jks $KEYSTORE
+fdroid_init_with_prebuilt_keystore $KEYSTORE
 test -e $KEYSTORE
 cp $WORKSPACE/tests/urzip.apk $REPOROOT/repo/
 $fdroid update --create-metadata --verbose
 $fdroid readmeta
 test -e repo/index.xml
 test -e repo/index.jar
+test -e repo/index-v1.jar
+test -e tmp/apkcache
+! test -z tmp/apkcache
 grep -F '<application id=' repo/index.xml > /dev/null
 
 # now set fake repo_keyalias
-sed -i 's,^ *repo_keyalias.*,repo_keyalias = "fake",' $REPOROOT/config.py
+$sed -i.tmp 's,^ *repo_keyalias.*,repo_keyalias = "fake",' $REPOROOT/config.py
 set +e
 $fdroid update
 if [ $? -eq 0 ]; then
@@ -536,6 +1010,66 @@ $fdroid update --create-key
 test -e $KEYSTORE
 
 
+#------------------------------------------------------------------------------#
+echo_header "sign binary repo in offline box, then publishing from online box"
+
+OFFLINE_ROOT=`create_test_dir`
+KEYSTORE=$WORKSPACE/tests/keystore.jks
+LOCAL_COPY_DIR=`create_test_dir`/fdroid
+mkdir $LOCAL_COPY_DIR
+ONLINE_ROOT=`create_test_dir`
+SERVERWEBROOT=`create_test_dir`
+
+# create offline binary transparency log
+cd $OFFLINE_ROOT
+mkdir binary_transparency
+cd binary_transparency
+git init
+
+# fake git remote server for binary transparency log
+BINARY_TRANSPARENCY_REMOTE=`create_test_dir`
+
+# fake git remote server for repo mirror
+SERVER_GIT_MIRROR=`create_test_dir`
+cd $SERVER_GIT_MIRROR
+git init
+if have_git_2_3; then
+    git config receive.denyCurrentBranch updateInstead
+fi
+
+cd $OFFLINE_ROOT
+fdroid_init_with_prebuilt_keystore
+cp -a $WORKSPACE/tests/metadata $WORKSPACE/tests/repo $WORKSPACE/tests/stats $OFFLINE_ROOT/
+
+echo "mirrors = ['http://foo.bar/fdroid', 'http://asdflkdsfjafdsdfhkjh.onion/fdroid']" >> config.py
+echo "servergitmirrors = '$SERVER_GIT_MIRROR'" >> config.py
+echo "local_copy_dir = '$LOCAL_COPY_DIR'" >> config.py
+echo "accepted_formats = ['json', 'txt', 'yml']" >> config.py
+$fdroid update --pretty
+grep -F '<application id=' repo/index.xml > /dev/null
+grep -F '/fdroid/repo</mirror>' repo/index.xml
+grep -F '/fdroid/archive</mirror>' archive/index.xml
+test `grep '<mirror>' repo/index.xml | wc -l` -eq 2
+test `grep '<mirror>' archive/index.xml | wc -l` -eq 2
+cd binary_transparency
+[ `git rev-list --count HEAD` == "1" ]
+cd ..
+$fdroid server update --verbose
+grep -F '<application id=' $LOCAL_COPY_DIR/repo/index.xml > /dev/null
+cd $ONLINE_ROOT
+echo "local_copy_dir = '$LOCAL_COPY_DIR'" >> config.py
+echo "sync_from_local_copy_dir = True" >> config.py
+echo "serverwebroots = '$SERVERWEBROOT'" >> config.py
+echo "servergitmirrors = '$SERVER_GIT_MIRROR'" >> config.py
+echo "local_copy_dir = '$LOCAL_COPY_DIR'" >> config.py
+echo "binary_transparency_remote = '$BINARY_TRANSPARENCY_REMOTE'" >> config.py
+$fdroid server update --verbose
+cd $BINARY_TRANSPARENCY_REMOTE
+[ `git rev-list --count HEAD` == "1" ]
+cd $SERVER_GIT_MIRROR
+[ `git rev-list --count HEAD` == "1" ]
+
+
 #------------------------------------------------------------------------------#
 
 # remove this to prevent git conflicts and complaining