diff --git a/getssl b/getssl
index 63436557..3bb6272e 100755
--- a/getssl
+++ b/getssl
@@ -266,6 +266,8 @@
 # 2021-07-22 Only pass +noidnout param to dig/drill(#682)(2.38)
 # 2021-07-25 Fix copy_file_to_location failures with ssh when suffix applied to file lacking an extension (tlhackque)(#686)
 # 2021-07-27 Support ftps://, FTPS_OPTIONS, remove default --insecure parameter to ftpes. Report caller(s) of error_exit in debug and test modes (tlhackque)(#687)(2.39)
+# 2021-07-30 Prefer API V2 when both offered (tlhackque) (#690) (2.40)
+# 2021-07-30 Run tests with -d to catch intermittent failures, Use fork's repo for upgrade tests. (tlhackque) (#692) (2.41)
 # ----------------------------------------------------------------------------------------
 
 case :$SHELLOPTS: in
@@ -274,7 +276,7 @@ esac
 
 PROGNAME=${0##*/}
 PROGDIR="$(cd "$(dirname "$0")" || exit; pwd -P;)"
-VERSION="2.39"
+VERSION="2.41"
 
 # defaults
 ACCOUNT_KEY_LENGTH=4096
@@ -284,7 +286,11 @@ CA="https://acme-staging-v02.api.letsencrypt.org/directory"
 CHALLENGE_CHECK_TYPE="http"
 CHECK_REMOTE_WAIT=0
 CHECK_REMOTE="true"
-CODE_LOCATION="https://raw.githubusercontent.com/srvrco/getssl/master/getssl"
+if [[ -n "${GITHUB_REPOSITORY}" ]] ; then
+  CODE_LOCATION="https://raw.githubusercontent.com/${GITHUB_REPOSITORY}/master/getssl"
+else
+  CODE_LOCATION="https://raw.githubusercontent.com/srvrco/getssl/master/getssl"
+fi
 CSR_SUBJECT="/"
 CURL_USERAGENT="${PROGNAME}/${VERSION}"
 DEACTIVATE_AUTH="false"
@@ -330,10 +336,12 @@ DNS_WAIT_RETRY_ADD="false"      # Try the dns_add_command again if the DNS recor
 # Private variables
 _CHECK_ALL=0
 _CREATE_CONFIG=0
+_CURL_VERSION=""
 _FORCE_RENEW=0
 _KEEP_VERSIONS=""
 _MUTE=0
 _NOTIFY_VALID=0
+_NOMETER=""
 _QUIET=0
 _RECREATE_CSR=0
 _REDIRECT_OUTPUT="1>/dev/null 2>&1"
@@ -562,7 +570,7 @@ check_challenge_completion_dns() { # perform validation via DNS challenge
         check_result=$($DNS_CHECK_FUNC $DNS_CHECK_OPTIONS TXT "${rr}" "@${ns}" \
                       | grep -i "^${rr}" \
                       | grep 'IN\WTXT'|awk -F'"' '{ print $2}')
-        debug "check_result=$check_result"
+        debug "check_result=\"$check_result\""
         if [[ -z "$check_result" ]]; then
           # shellcheck disable=SC2086
           debug "$DNS_CHECK_FUNC" $DNS_CHECK_OPTIONS ANY "${rr}" "@${ns}"
@@ -570,7 +578,7 @@ check_challenge_completion_dns() { # perform validation via DNS challenge
           check_result=$($DNS_CHECK_FUNC $DNS_CHECK_OPTIONS ANY "${rr}" "@${ns}" \
                       | grep -i "^${rr}" \
                       | grep 'IN\WTXT'|awk -F'"' '{ print $2}')
-          debug "check_result=$check_result"
+          debug "check_result=\"$check_result\""
         fi
       elif [[ "$DNS_CHECK_FUNC" == "host" ]]; then
         check_result=$($DNS_CHECK_FUNC -t TXT "${rr}" "${ns}" \
@@ -583,8 +591,8 @@ check_challenge_completion_dns() { # perform validation via DNS challenge
                       | grep 'text ='|awk -F'"' '{ print $2}')
         fi
       fi
-      debug "expecting  $auth_key"
-      debug "${ns} gave ... $check_result"
+      debug "expecting  \"$auth_key\""
+      debug "${ns} gave ... \"$check_result\""
 
       if [[ "$check_result" == *"$auth_key"* ]]; then
         check_dns="success"
@@ -606,7 +614,7 @@ check_challenge_completion_dns() { # perform validation via DNS challenge
           debug "dns check failed - removing existing value"
           del_dns_rr "${d}" "${auth_key}"
 
-          error_exit "checking ${rr} gave $check_result not $auth_key"
+          error_exit "checking \"${rr}\" gave \"$check_result\" not \"$auth_key\""
         fi
       fi
     done
@@ -758,7 +766,7 @@ check_getssl_upgrade() { # check if a more recent version of code is available a
   if [ "$TEMP_UPGRADE_FILE" == "" ]; then
     error_exit "mktemp failed"
   fi
-  curl --user-agent "$CURL_USERAGENT" --silent "$CODE_LOCATION" --output "$TEMP_UPGRADE_FILE"
+  curl ${_NOMETER} --user-agent "$CURL_USERAGENT" --silent "$CODE_LOCATION" --output "$TEMP_UPGRADE_FILE"
   errcode=$?
   if [[ $errcode -eq 60 ]]; then
     error_exit "curl needs updating, your version does not support SNI (multiple SSL domains on a single IP)"
@@ -941,7 +949,7 @@ copy_file_to_location() { # copies a file, using scp, sftp or ftp if required.
       fromfile=$(basename "$from")
       debug "davs user=$davsuser - pass=$davspass - host=$davshost port=$davsport dir=$davsdirn file=$davsfile"
       debug "from dir=$fromdir  file=$fromfile"
-      curl -u "${davsuser}:${davspass}" -T "${fromdir}/${fromfile}" "https://${davshost}:${davsport}${davsdirn}${davsfile}"
+      curl ${_NOMETER} -u "${davsuser}:${davspass}" -T "${fromdir}/${fromfile}" "https://${davshost}:${davsport}${davsdirn}${davsfile}"
     elif [[ "${to:0:6}" == "ftpes:" ]] || [[ "${to:0:5}" == "ftps:" ]] ; then
       debug "using ftp to copy the file from $from"
       ftpuser=$(echo "$to"| awk -F: '{print $2}')
@@ -956,10 +964,10 @@ copy_file_to_location() { # copies a file, using scp, sftp or ftp if required.
       debug "from dir=$fromdir  file=$fromfile"
       if [[ "${to:0:5}" == "ftps:" ]] ; then
         # shellcheck disable=SC2086
-        curl $FTPS_OPTIONS --ftp-ssl --ftp-ssl-reqd -u "${ftpuser}:${ftppass}" -T "${fromdir}/${fromfile}" "ftp://${ftphost}${ftpdirn}:990/"
+        curl ${_NOMETER} $FTPS_OPTIONS --ftp-ssl --ftp-ssl-reqd -u "${ftpuser}:${ftppass}" -T "${fromdir}/${fromfile}" "ftp://${ftphost}${ftpdirn}:990/"
       else
         # shellcheck disable=SC2086
-        curl $FTPS_OPTIONS --ftp-ssl --ftp-ssl-reqd -u "${ftpuser}:${ftppass}" -T "${fromdir}/${fromfile}" "ftp://${ftphost}${ftpdirn}/"
+        curl ${_NOMETER} $FTPS_OPTIONS --ftp-ssl --ftp-ssl-reqd -u "${ftpuser}:${ftppass}" -T "${fromdir}/${fromfile}" "ftp://${ftphost}${ftpdirn}/"
       fi
     else
       if ! mkdir -p "$(dirname "$to")" ; then
@@ -1377,7 +1385,7 @@ for d in "${alldomains[@]}"; do
         # ACME only allows port 80 (http), but redirects may use https.  --insecure is used in case
         # those certificates are being renewed.  Let's Encrypt does the same.  In this case, we verify
         # that the correct data is returned, so this is safe.
-        if [[ ! "$(curl --user-agent "$CURL_USERAGENT" --insecure --silent --location "$wellknown_url")" == "$keyauthorization" ]]; then
+        if [[ ! "$(curl ${_NOMETER} --user-agent "$CURL_USERAGENT" --insecure --silent --location "$wellknown_url")" == "$keyauthorization" ]]; then
           error_exit "for some reason could not reach $wellknown_url - please check it manually"
         fi
       fi
@@ -1621,7 +1629,7 @@ get_certificate() { # get certificate for csr, if all domains validated.
     CertData=$(awk ' $1 ~ "^Location" {print $2}' "$CURL_HEADER" |tr -d '\r')
     if [[ "$CertData" ]] ; then
       echo -----BEGIN CERTIFICATE----- > "$gc_certfile"
-      curl --user-agent "$CURL_USERAGENT" --silent "$CertData" | openssl base64 -e  >> "$gc_certfile"
+      curl ${_NOMETER} --user-agent "$CURL_USERAGENT" --silent "$CertData" | openssl base64 -e  >> "$gc_certfile"
       echo -----END CERTIFICATE-----  >> "$gc_certfile"
       info "Certificate saved in $CERT_FILE"
     fi
@@ -1641,7 +1649,7 @@ get_certificate() { # get certificate for csr, if all domains validated.
                 | sed 's/>//g')
     if [[ "$IssuerData" ]] ; then
       echo -----BEGIN CERTIFICATE----- > "$gc_cafile"
-      curl --user-agent "$CURL_USERAGENT" --silent "$IssuerData" | openssl base64 -e  >> "$gc_cafile"
+      curl ${_NOMETER} --user-agent "$CURL_USERAGENT" --silent "$IssuerData" | openssl base64 -e  >> "$gc_cafile"
       echo -----END CERTIFICATE-----  >> "$gc_cafile"
       info "The intermediate CA cert is in $gc_cafile"
     fi
@@ -1699,7 +1707,7 @@ get_certificate() { # get certificate for csr, if all domains validated.
       cp "$gc_certfile" "$gc_fullchain"
       while [[ -n "$issuer_url" ]]; do
         debug Fetching certificate issuer from "$issuer_url"
-        issuer_cert=$(curl --user-agent "$CURL_USERAGENT" --silent "$issuer_url" | openssl x509 -inform der -outform pem)
+        issuer_cert=$(curl ${_NOMETER} --user-agent "$CURL_USERAGENT" --silent "$issuer_url" | openssl x509 -inform der -outform pem)
         debug Fetched issuer certificate "$(echo "$issuer_cert" | openssl x509 -inform pem -noout -text | awk 'BEGIN {FS="Subject: "} NF==2 {print $2; exit}')"
         echo "$issuer_cert" >> "$gc_fullchain"
 
@@ -1714,7 +1722,7 @@ get_certificate() { # get certificate for csr, if all domains validated.
 get_cr() { # get curl response
   url="$1"
   debug url "$url"
-  response=$(curl --user-agent "$CURL_USERAGENT" --silent "$url")
+  response=$(curl ${_NOMETER} --user-agent "$CURL_USERAGENT" --silent "$url")
   ret=$?
   debug response "${response//[$'\t\r\n']}"
   code=$(json_get "$response" status)
@@ -1797,7 +1805,7 @@ get_signing_params() { # get signing parameters from key
 }
 
 graceful_exit() { # normal exit function.
-  exit_code=$1
+  exit_code="${1-0}"
   clean_up
   # shellcheck disable=SC2086
   exit $exit_code
@@ -2055,7 +2063,7 @@ obtain_ca_resource_locations()
   for suffix in "" "/directory" "/dir";
   do
     # Obtain CA resource locations
-    ca_all_loc=$(curl --user-agent "$CURL_USERAGENT" "${CA}${suffix}" 2>/dev/null)
+    ca_all_loc=$(curl ${_NOMETER} --user-agent "$CURL_USERAGENT" "${CA}${suffix}" 2>/dev/null)
     debug "ca_all_loc from ${CA}${suffix} gives $ca_all_loc"
     # APIv1
     URL_new_reg=$(echo "$ca_all_loc" | grep "new-reg" | awk -F'"' '{print $4}')
@@ -2072,10 +2080,11 @@ obtain_ca_resource_locations()
     fi
   done
 
-  if [[ -n "$URL_new_reg" ]]; then
-    API=1
-  elif [[ -n "$URL_newAccount" ]]; then
+  # If a directory offers both versions, select V2.
+  if [[ -n "$URL_newAccount" ]]; then
     API=2
+  elif [[ -n "$URL_new_reg" ]]; then
+    API=1
   else
     error_exit "unknown API version"
   fi
@@ -2236,9 +2245,9 @@ send_signed_request() { # Sends a request to the ACME server, signed with your p
   CURL_HEADER="$TEMP_DIR/curl.header"
   dp="$TEMP_DIR/curl.dump"
 
-  CURL="curl "
+  CURL="curl ${_NOMETER} "
   # shellcheck disable=SC2072
-  if [[ "$($CURL -V | head -1 | cut -d' ' -f2 )" > "7.33" ]]; then
+  if [[ ! "${_CURL_VERSION}" < "7.33" ]]; then
     CURL="$CURL --http1.1 "
   fi
 
@@ -2314,7 +2323,7 @@ send_signed_request() { # Sends a request to the ACME server, signed with your p
       fi
 
       if [[ $errcode -gt 0 || ( "$response" == "" && $url != *"revoke"* ) ]]; then
-        error_exit "ERROR curl \"$url\" failed with $errcode and returned $response"
+        error_exit "ERROR curl \"$url\" failed with $errcode and returned \"$response\""
       fi
 
       responseHeaders=$(cat "$CURL_HEADER")
@@ -2414,13 +2423,14 @@ signal_exit() { # Handle trapped signals
 }
 
 traceback() { # Print function traceback
-    local i d=1 lbl=" called"
-    echo "Traceback" >&2
-    for ((i=$((${#FUNCNAME[@]}-1)); i>0; i--)); do
-      if [[ ${i} -eq 1 ]] ; then lbl=" called traceback" ; fi
-      printf "%*s%s() line %d%s\n" "$d" '' "${FUNCNAME[$i]}" "${BASH_LINENO[$((i-1))]}" "$lbl" >&2
-      ((d++))
-    done
+  local i d=1 lbl=" called"
+  debug "Traceback"
+  for ((i=$((${#FUNCNAME[@]}-1)); i>0; i--)); do
+    if [[ ${i} -eq 1 ]] ; then lbl=" called traceback" ; fi
+    debug "$(printf "%*s%s() line %d%s\n" "$d" '' "${FUNCNAME[$i]}" "${BASH_LINENO[$((i-1))]}" "$lbl")"
+    ((d++))
+  done
+  return 0
 }
 
 urlbase64() { # urlbase64: base64 encoded string with '+' replaced with '-' and '/' replaced with '_'
@@ -2625,6 +2635,12 @@ write_openssl_conf() { # write out a minimal openssl conf
 trap "signal_exit TERM" TERM HUP
 trap "signal_exit INT"  INT
 
+# When running tests, use debug mode to capture intermittent faults
+# Test harness will Save output in a temporary file, which is displayed if an error occurs
+if [[ ${_RUNNING_TEST} -eq 1 ]] ; then
+  _USE_DEBUG=1
+fi
+
 # Parse command-line
 while [[ -n ${1+defined} ]]; do
   case $1 in
@@ -2720,6 +2736,17 @@ requires sed
 requires sort
 requires mktemp
 
+# Make sure cURL doesn't display a progress meter (if it's new enough)
+# --silent also does this, but suppresses warnings and informational messages too.
+# TODO: see where --silent can be removed (if _NOMETER defaults to --silent for old versions?)
+#       This would help with debugging transfer errors.
+
+_CURL_VERSION="$(curl -V | head -1 | cut -d' ' -f2 )"
+# shellcheck disable=SC2072
+if [[ ! "${_CURL_VERSION}" < "7.67" ]]; then
+    _NOMETER="--no-progress-meter"
+fi
+
 # Check if upgrades are available (unless they have specified -U to ignore Upgrade checks)
 if [[ $_UPGRADE_CHECK -eq 1 ]]; then
   check_getssl_upgrade
diff --git a/test/1-simple-http01-dig.bats b/test/1-simple-http01-dig.bats
index be01f273..6c29ec67 100644
--- a/test/1-simple-http01-dig.bats
+++ b/test/1-simple-http01-dig.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     if [ -f /usr/bin/host ]; then
         mv /usr/bin/host /usr/bin/host.getssl.bak
@@ -18,6 +19,7 @@ setup() {
 
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     if [ -f /usr/bin/host.getssl.bak ]; then
         mv /usr/bin/host.getssl.bak /usr/bin/host
     fi
diff --git a/test/1-simple-http01-nslookup.bats b/test/1-simple-http01-nslookup.bats
index 78d175a9..aa71e1c4 100644
--- a/test/1-simple-http01-nslookup.bats
+++ b/test/1-simple-http01-nslookup.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     if [ -f /usr/bin/dig ]; then
         mv /usr/bin/dig /usr/bin/dig.getssl.bak
@@ -18,6 +19,7 @@ setup() {
 
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     if [ -f /usr/bin/dig.getssl.bak ]; then
         mv /usr/bin/dig.getssl.bak /usr/bin/dig
     fi
diff --git a/test/1-simple-http01-two-acl.bats b/test/1-simple-http01-two-acl.bats
index 0169bd08..b4bb3f1a 100644
--- a/test/1-simple-http01-two-acl.bats
+++ b/test/1-simple-http01-two-acl.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 }
 
diff --git a/test/1-simple-http01.bats b/test/1-simple-http01.bats
index a57010b7..518f734c 100644
--- a/test/1-simple-http01.bats
+++ b/test/1-simple-http01.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 }
 
diff --git a/test/10-mixed-case.bats b/test/10-mixed-case.bats
index 974f6694..382f19a4 100644
--- a/test/10-mixed-case.bats
+++ b/test/10-mixed-case.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/11-test--install.bats b/test/11-test--install.bats
index e0343262..1ab1ca48 100644
--- a/test/11-test--install.bats
+++ b/test/11-test--install.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 }
 
diff --git a/test/11-test-no-domain-storage.bats b/test/11-test-no-domain-storage.bats
index 3be0be58..9ad4aa47 100644
--- a/test/11-test-no-domain-storage.bats
+++ b/test/11-test-no-domain-storage.bats
@@ -5,6 +5,13 @@ load '/bats-assert/load.bash'
 load '/getssl/test/test_helper.bash'
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Check that if domain storage isn't set getssl doesn't try to delete /tmp" {
     if [ -n "$STAGING" ]; then
         skip "Using staging server, skipping internal test"
diff --git a/test/12-auto-upgrade-v1.bats b/test/12-auto-upgrade-v1.bats
index 4165cd3f..75545611 100644
--- a/test/12-auto-upgrade-v1.bats
+++ b/test/12-auto-upgrade-v1.bats
@@ -5,6 +5,13 @@ load '/bats-assert/load.bash'
 load '/getssl/test/test_helper.bash'
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Check that auto upgrade to v2 doesn't change pebble url" {
     if [ -n "$STAGING" ]; then
         skip "Using staging server, skipping internal test"
@@ -19,6 +26,13 @@ load '/getssl/test/test_helper.bash'
 }
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Check that auto upgrade to v2 doesn't change v2 staging url" {
     if [ -n "$STAGING" ]; then
         skip "Using staging server, skipping internal test"
@@ -33,6 +47,13 @@ load '/getssl/test/test_helper.bash'
 }
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Check that auto upgrade to v2 doesn't change v2 prod url" {
     if [ -n "$STAGING" ]; then
         skip "Using staging server, skipping internal test"
@@ -47,6 +68,13 @@ load '/getssl/test/test_helper.bash'
 }
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Check that auto upgrade to v2 changes v1 staging to v2 staging url" {
     if [ -n "$STAGING" ]; then
         skip "Using staging server, skipping internal test"
@@ -61,6 +89,13 @@ load '/getssl/test/test_helper.bash'
 }
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Check that auto upgrade to v2 changes v1 prod to v2 prod url" {
     if [ -n "$STAGING" ]; then
         skip "Using staging server, skipping internal test"
diff --git a/test/13-notify-valid.bats b/test/13-notify-valid.bats
index ac1a50c6..6b669278 100644
--- a/test/13-notify-valid.bats
+++ b/test/13-notify-valid.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 }
 
diff --git a/test/14-test-revoke.bats b/test/14-test-revoke.bats
index d31e832b..fffe300b 100644
--- a/test/14-test-revoke.bats
+++ b/test/14-test-revoke.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/15-test-revoke-no-suffix.bats b/test/15-test-revoke-no-suffix.bats
index 30802d8b..3eb273c6 100644
--- a/test/15-test-revoke-no-suffix.bats
+++ b/test/15-test-revoke-no-suffix.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/16-test-bad-acl.bats b/test/16-test-bad-acl.bats
index d9539518..e2feec53 100644
--- a/test/16-test-bad-acl.bats
+++ b/test/16-test-bad-acl.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 }
 
diff --git a/test/17-test-spaces-in-sans-dns01.bats b/test/17-test-spaces-in-sans-dns01.bats
index 9d425af6..574866db 100644
--- a/test/17-test-spaces-in-sans-dns01.bats
+++ b/test/17-test-spaces-in-sans-dns01.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/17-test-spaces-in-sans-http01.bats b/test/17-test-spaces-in-sans-http01.bats
index 1730e99c..0947e065 100644
--- a/test/17-test-spaces-in-sans-http01.bats
+++ b/test/17-test-spaces-in-sans-http01.bats
@@ -6,7 +6,13 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/18-retry-dns-add.bats b/test/18-retry-dns-add.bats
index 25318de1..80244aad 100644
--- a/test/18-retry-dns-add.bats
+++ b/test/18-retry-dns-add.bats
@@ -5,7 +5,12 @@ load '/bats-assert/load.bash'
 load '/getssl/test/test_helper.bash'
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 }
 
diff --git a/test/19-test-add-to-sans.bats b/test/19-test-add-to-sans.bats
index a0a6d718..945432a9 100644
--- a/test/19-test-add-to-sans.bats
+++ b/test/19-test-add-to-sans.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
         curl --silent -X POST -d '{"host":"a.'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
@@ -14,6 +15,7 @@ setup() {
 }
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     if [ -z "$STAGING" ]; then
         curl --silent -X POST -d '{"host":"a.'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/clear-a
     fi
diff --git a/test/2-simple-dns01-dig.bats b/test/2-simple-dns01-dig.bats
index a0d70a2f..c0edf7b9 100644
--- a/test/2-simple-dns01-dig.bats
+++ b/test/2-simple-dns01-dig.bats
@@ -28,6 +28,13 @@ teardown_file() {
 }
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Create new certificate using DNS-01 verification (dig)" {
     CONFIG_FILE="getssl-dns01.cfg"
 
@@ -40,6 +47,13 @@ teardown_file() {
 }
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Force renewal of certificate using DNS-01 (dig)" {
     run ${CODE_DIR}/getssl -d -f $GETSSL_HOST
     assert_success
diff --git a/test/2-simple-dns01-nslookup.bats b/test/2-simple-dns01-nslookup.bats
index f97b5dc4..c0b73834 100644
--- a/test/2-simple-dns01-nslookup.bats
+++ b/test/2-simple-dns01-nslookup.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
@@ -20,6 +21,7 @@ setup() {
 
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     if [ -f /usr/bin/dig.getssl.bak ]; then
         mv /usr/bin/dig.getssl.bak /usr/bin/dig
     fi
diff --git a/test/20-wildcard-simple.bats b/test/20-wildcard-simple.bats
index b56a876e..eb0544f8 100644
--- a/test/20-wildcard-simple.bats
+++ b/test/20-wildcard-simple.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/21-wildcard-dual-rsa.bats b/test/21-wildcard-dual-rsa.bats
index 550bbe0f..97e23cb5 100644
--- a/test/21-wildcard-dual-rsa.bats
+++ b/test/21-wildcard-dual-rsa.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/22-wildcard-dual-rsa-ecdsa-copy-2-locations.bats b/test/22-wildcard-dual-rsa-ecdsa-copy-2-locations.bats
index b005af5d..4d6e1155 100644
--- a/test/22-wildcard-dual-rsa-ecdsa-copy-2-locations.bats
+++ b/test/22-wildcard-dual-rsa-ecdsa-copy-2-locations.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # These are run for every test, not once per file
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/23-wildcard-check-globbing.bats b/test/23-wildcard-check-globbing.bats
index 1c812b19..bf742308 100644
--- a/test/23-wildcard-check-globbing.bats
+++ b/test/23-wildcard-check-globbing.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/24-wildcard-sans.bats b/test/24-wildcard-sans.bats
index a9ca2a58..500acd45 100644
--- a/test/24-wildcard-sans.bats
+++ b/test/24-wildcard-sans.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
         curl --silent -X POST -d '{"host":"wild-'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
@@ -15,6 +16,7 @@ setup() {
 
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     if [ -z "$STAGING" ]; then
         curl --silent -X POST -d '{"host":"wild-'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/clear-a
     fi
diff --git a/test/25-wildcard-all.bats b/test/25-wildcard-all.bats
index 8e428ab0..4a74912d 100644
--- a/test/25-wildcard-all.bats
+++ b/test/25-wildcard-all.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/26-wildcard-revoke.bats b/test/26-wildcard-revoke.bats
index 37f8f10e..e613c1ea 100644
--- a/test/26-wildcard-revoke.bats
+++ b/test/26-wildcard-revoke.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/27-wildcard-existing-cert.bats b/test/27-wildcard-existing-cert.bats
index 76f2aa71..a9e83be2 100644
--- a/test/27-wildcard-existing-cert.bats
+++ b/test/27-wildcard-existing-cert.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/28-wildcard-error-http01-validation.bats b/test/28-wildcard-error-http01-validation.bats
index dbb64b7f..3c08e724 100644
--- a/test/28-wildcard-error-http01-validation.bats
+++ b/test/28-wildcard-error-http01-validation.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/29-check-mktemp-failure.bats b/test/29-check-mktemp-failure.bats
index 782dc649..81b9ae4d 100644
--- a/test/29-check-mktemp-failure.bats
+++ b/test/29-check-mktemp-failure.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/3-dual-rsa-ecdsa.bats b/test/3-dual-rsa-ecdsa.bats
index 87527c2e..df8a8fc9 100644
--- a/test/3-dual-rsa-ecdsa.bats
+++ b/test/3-dual-rsa-ecdsa.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 }
 
diff --git a/test/30-handle-dig-failure.bats b/test/30-handle-dig-failure.bats
index 11027451..898ac4da 100644
--- a/test/30-handle-dig-failure.bats
+++ b/test/30-handle-dig-failure.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     if [ -f /usr/bin/drill ]; then
         mv /usr/bin/drill /usr/bin/drill.getssl.bak
@@ -18,6 +19,7 @@ setup() {
 
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     if [ -f /usr/bin/drill.getssl.bak ]; then
         mv /usr/bin/drill.getssl.bak /usr/bin/drill
     fi
diff --git a/test/31-test-posix-error.bats b/test/31-test-posix-error.bats
index e9950fdf..7623cae3 100644
--- a/test/31-test-posix-error.bats
+++ b/test/31-test-posix-error.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 }
 
diff --git a/test/32-test-upgrade.bats b/test/32-test-upgrade.bats
index f8fc68a5..1a311d7f 100644
--- a/test/32-test-upgrade.bats
+++ b/test/32-test-upgrade.bats
@@ -7,11 +7,17 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 
     # Turn off warning about detached head
     git config --global advice.detachedHead false
-    run git clone https://github.com/srvrco/getssl.git "$INSTALL_DIR/upgrade-getssl"
+    if [[ -n "${GITHUB_REPOSITORY}" ]] ; then
+      _REPO="https://github.com/${GITHUB_REPOSITORY}.git"
+    else
+      _REPO="https://github.com/srvrco/getssl.git"
+    fi
+    run git clone "${_REPO}" "$INSTALL_DIR/upgrade-getssl"
 
     # Don't do version arithmetics any longer, look what was the previous version by getting the last
     # line (starting with v) and the one before that from the list of tags.
@@ -27,7 +33,9 @@ setup() {
 
 
 teardown() {
-    rm -r "$INSTALL_DIR/upgrade-getssl"
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+    [ -d "$INSTALL_DIR/upgrade-getssl" ] && rm -r "$INSTALL_DIR/upgrade-getssl"
+    true
 }
 
 
diff --git a/test/33-ftp.bats b/test/33-ftp.bats
index 9c2e3870..086636a7 100644
--- a/test/33-ftp.bats
+++ b/test/33-ftp.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     if [ -n "${VSFTPD_CONF}" ]; then
         cp $VSFTPD_CONF ${VSFTPD_CONF}.getssl
@@ -23,6 +24,7 @@ _FTP
 
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     if [ -n "${VSFTPD_CONF}" ]; then
         cp ${VSFTPD_CONF}.getssl $VSFTPD_CONF
         ${CODE_DIR}/test/restart-ftpd
diff --git a/test/34-ftp-passive.bats b/test/34-ftp-passive.bats
index 0d165747..ac6e2220 100644
--- a/test/34-ftp-passive.bats
+++ b/test/34-ftp-passive.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     if [ -n "${VSFTPD_CONF}" ]; then
         cp $VSFTPD_CONF ${VSFTPD_CONF}.getssl
@@ -26,6 +27,7 @@ _FTP
 
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     if [ -n "${VSFTPD_CONF}" ]; then
         cp ${VSFTPD_CONF}.getssl $VSFTPD_CONF
         ${CODE_DIR}/test/restart-ftpd
diff --git a/test/35-preferred-chain.bats b/test/35-preferred-chain.bats
index 9c3fc6ba..0ffe71e2 100644
--- a/test/35-preferred-chain.bats
+++ b/test/35-preferred-chain.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/36-full-chain-inc-root.bats b/test/36-full-chain-inc-root.bats
index 5b29d0b5..46550754 100644
--- a/test/36-full-chain-inc-root.bats
+++ b/test/36-full-chain-inc-root.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     fi
diff --git a/test/37-idn.bats b/test/37-idn.bats
index be624de0..a3cf43a2 100644
--- a/test/37-idn.bats
+++ b/test/37-idn.bats
@@ -13,6 +13,7 @@ setup_file() {
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     GETSSL_CMD_HOST=${GETSSL_IDN_HOST}
 
     # use the test description to move tools we don't want to test out of the way
@@ -26,6 +27,7 @@ setup() {
 }
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     # use the test description to move tools we didn't want to test back
     DNS_TOOL=${BATS_TEST_DESCRIPTION##*-}
     for tool in dig drill host nslookup
diff --git a/test/38-idn-http01-check-noidnout.bats b/test/38-idn-http01-check-noidnout.bats
index fde4fe66..6ba8d148 100644
--- a/test/38-idn-http01-check-noidnout.bats
+++ b/test/38-idn-http01-check-noidnout.bats
@@ -11,7 +11,12 @@ setup_file() {
     fi
 }
 
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     GETSSL_CMD_HOST=$GETSSL_IDN_HOST
 }
 
diff --git a/test/4-more-than-10-hosts.bats b/test/4-more-than-10-hosts.bats
index f4eb95c0..f62d2e6f 100644
--- a/test/4-more-than-10-hosts.bats
+++ b/test/4-more-than-10-hosts.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 }
 
diff --git a/test/5-secp384-http01.bats b/test/5-secp384-http01.bats
index 3d05159b..5ddf0d62 100644
--- a/test/5-secp384-http01.bats
+++ b/test/5-secp384-http01.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 }
 
diff --git a/test/6-dual-rsa-ecdsa-copy-2-locations.bats b/test/6-dual-rsa-ecdsa-copy-2-locations.bats
index 6f75f25f..16ca162a 100644
--- a/test/6-dual-rsa-ecdsa-copy-2-locations.bats
+++ b/test/6-dual-rsa-ecdsa-copy-2-locations.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # These are run for every test, not once per file
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
         curl --silent -X POST -d '{"host":"'a.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
@@ -15,6 +16,7 @@ setup() {
 
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     if [ -z "$STAGING" ]; then
         curl --silent -X POST -d '{"host":"'a.$GETSSL_HOST'"}' http://10.30.50.3:8055/clear-a
     fi
diff --git a/test/7-test-renewal.bats b/test/7-test-renewal.bats
index 074f8821..a2e9e0c7 100644
--- a/test/7-test-renewal.bats
+++ b/test/7-test-renewal.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     if [ -z "$STAGING" ]; then
         export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
         curl --silent -X POST -d '{"host":"a.'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
@@ -15,6 +16,7 @@ setup() {
 }
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     if [ -z "$STAGING" ]; then
         curl --silent -X POST -d '{"host":"a.'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/clear-a
         curl --silent -X POST -d '{"host":"b.'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/clear-a
diff --git a/test/8-staging-ecdsa.bats b/test/8-staging-ecdsa.bats
index 6aebd601..67e657a1 100644
--- a/test/8-staging-ecdsa.bats
+++ b/test/8-staging-ecdsa.bats
@@ -7,6 +7,13 @@ load '/getssl/test/test_helper.bash'
 
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Create new certificate using staging server and prime256v1" {
     if [ -z "$STAGING" ]; then
         skip "Running external tests, skipping internal testing"
@@ -22,6 +29,13 @@ load '/getssl/test/test_helper.bash'
 }
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Force renewal of certificate using staging server and prime256v1" {
     if [ -z "$STAGING" ]; then
         skip "Running internal tests, skipping external test"
@@ -33,6 +47,13 @@ load '/getssl/test/test_helper.bash'
 }
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Create new certificate using staging server and secp384r1" {
     if [ -z "$STAGING" ]; then
         skip "Running external tests, skipping internal testing"
@@ -48,6 +69,13 @@ load '/getssl/test/test_helper.bash'
 }
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Force renewal of certificate using staging server and secp384r1" {
     if [ -z "$STAGING" ]; then
         skip "Running internal tests, skipping external test"
diff --git a/test/9-multiple-domains-dns01.bats b/test/9-multiple-domains-dns01.bats
index 65eab09a..12bb2e1a 100644
--- a/test/9-multiple-domains-dns01.bats
+++ b/test/9-multiple-domains-dns01.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
 }
 
diff --git a/test/9-test--all.bats b/test/9-test--all.bats
index cb043a54..35697fd5 100644
--- a/test/9-test--all.bats
+++ b/test/9-test--all.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
     export PATH=$PATH:/getssl
 }
diff --git a/test/dns_add_fail b/test/dns_add_fail
index c39a89a9..b8aa2b8e 100755
--- a/test/dns_add_fail
+++ b/test/dns_add_fail
@@ -2,5 +2,5 @@
 
 # Special test script which will always fail to update dns
 
-echo "This is a test script to check retry works if DNS isn't updated"
+echo "dns_add_fail: This is a test script to check retry works if DNS isn't updated"
 exit 0
diff --git a/test/run-test.sh b/test/run-test.sh
index c3852ef2..76a7555f 100755
--- a/test/run-test.sh
+++ b/test/run-test.sh
@@ -37,6 +37,7 @@ docker run \
   --env GETSSL_HOST=$ALIAS $STAGING \
   --env GETSSL_IDN_HOST=$GETSSL_IDN_HOST \
   --env GETSSL_OS=$GETSSL_OS \
+  --env GITHUB_REPOSITORY="${GITHUB_REPOSITORY}" \
   -v "$(pwd)":/getssl \
   --rm \
   --network ${PWD##*/}_acmenet \
diff --git a/test/test_helper.bash b/test/test_helper.bash
index ea71967d..0827adfa 100644
--- a/test/test_helper.bash
+++ b/test/test_helper.bash
@@ -25,7 +25,7 @@ check_nginx() {
 check_output_for_errors() {
   refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]'
   # less strict tests if running with debug output
-  if [ -n "$1" ]; then
+  if [ -n "X$1" ]; then
       # don't fail for :error:badNonce
       refute_output --regexp '[^:][Ee][Rr][Rr][Oo][Rr][^:]'
       # don't check for "Warnings:" as there might be a warning message if nslookup doesn't support -debug (alpine/ubuntu)
@@ -47,12 +47,12 @@ create_certificate() {
   # Create certificate
   cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl.cfg"
   # shellcheck disable=SC2086
-  run ${CODE_DIR}/getssl "$@" "$GETSSL_CMD_HOST"
+  run ${CODE_DIR}/getssl -d "$@" "$GETSSL_CMD_HOST"
 }
 
 init_getssl() {
   # Run initialisation (create account key, etc)
-  run ${CODE_DIR}/getssl -c "$GETSSL_CMD_HOST"
+  run ${CODE_DIR}/getssl -d -c "$GETSSL_CMD_HOST"
   assert_success
   [ -d "$INSTALL_DIR/.getssl" ]
 }
diff --git a/test/u1-test-get_auth_dns-dig.bats b/test/u1-test-get_auth_dns-dig.bats
index ac11c1d1..24ab0883 100644
--- a/test/u1-test-get_auth_dns-dig.bats
+++ b/test/u1-test-get_auth_dns-dig.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     for app in drill host nslookup
     do
         if [ -f /usr/bin/${app} ]; then
@@ -22,6 +23,7 @@ setup() {
 
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     for app in drill host nslookup
     do
         if [ -f /usr/bin/${app}.getssl.bak ]; then
diff --git a/test/u2-test-get_auth_dns-drill.bats b/test/u2-test-get_auth_dns-drill.bats
index d20079cc..b63cf1b1 100644
--- a/test/u2-test-get_auth_dns-drill.bats
+++ b/test/u2-test-get_auth_dns-drill.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     for app in dig host nslookup
     do
         if [ -f /usr/bin/${app} ]; then
@@ -22,6 +23,7 @@ setup() {
 
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     for app in dig host nslookup
     do
         if [ -f /usr/bin/${app}.getssl.bak ]; then
diff --git a/test/u3-mktemp-template.bats b/test/u3-mktemp-template.bats
index 2cb8040b..e28208cf 100644
--- a/test/u3-mktemp-template.bats
+++ b/test/u3-mktemp-template.bats
@@ -5,6 +5,13 @@ load '/bats-assert/load.bash'
 load '/getssl/test/test_helper.bash'
 
 
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+}
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 @test "Check mktemp -t getssl.XXXXXX works on all platforms" {
     run mktemp -t getssl.XXXXXX
     assert_success
diff --git a/test/u4-create-csr-and-ifs.bats b/test/u4-create-csr-and-ifs.bats
index 344a536c..7871445d 100644
--- a/test/u4-create-csr-and-ifs.bats
+++ b/test/u4-create-csr-and-ifs.bats
@@ -6,7 +6,12 @@ load '/getssl/test/test_helper.bash'
 
 
 # This is run for every test
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     . /getssl/getssl --source
     find_dns_utils
     _RUNNING_TEST=1
diff --git a/test/u5-test-get_auth_dns-no-root-servers.bats b/test/u5-test-get_auth_dns-no-root-servers.bats
index d218eb90..7dcbdc9f 100644
--- a/test/u5-test-get_auth_dns-no-root-servers.bats
+++ b/test/u5-test-get_auth_dns-no-root-servers.bats
@@ -7,6 +7,7 @@ load '/getssl/test/test_helper.bash'
 
 # This is run for every test
 setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
     cp /etc/resolv.conf /etc/resolv.conf.getssl
     cat <<- EOF > /etc/resolv.conf
 nameserver 8.8.8.8
@@ -28,6 +29,7 @@ EOF
 
 
 teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
     cat /etc/resolv.conf.getssl > /etc/resolv.conf
     for app in drill host nslookup
     do
diff --git a/test/u6-test-combined-directory.bats b/test/u6-test-combined-directory.bats
new file mode 100644
index 00000000..4ef0d1f4
--- /dev/null
+++ b/test/u6-test-combined-directory.bats
@@ -0,0 +1,34 @@
+#! /usr/bin/env bats
+
+load '/bats-support/load.bash'
+load '/bats-assert/load.bash'
+load '/getssl/test/test_helper.bash'
+
+# CA with a unified directory (both ACME V1 and V2 at the same URI)
+CA="https://api.test4.buypass.no/acme"
+
+# This is run for every test
+setup() {
+    [ ! -f $BATS_TMPDIR/failed.skip ] || skip "skipping tests after first failure"
+
+    . /getssl/getssl --source
+
+    requires curl
+    _NOMETER="--silent"
+
+    _RUNNING_TEST=1
+    _USE_DEBUG=1
+}
+
+
+teardown() {
+    [ -n "$BATS_TEST_COMPLETED" ] || touch $BATS_TMPDIR/failed.skip
+}
+
+
+@test "Check that API V2 is selected in a unified ACME directory." {
+    obtain_ca_resource_locations
+    
+    [ "$API" -eq 2 ]
+}
+