aboutsummaryrefslogtreecommitdiff
path: root/src/auditor
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2020-03-26 17:21:41 +0100
committerChristian Grothoff <christian@grothoff.org>2020-03-26 17:21:41 +0100
commit28c00bedbf2a936d6b888169d06130bd27a0caaf (patch)
treedbc21d3a7c3d8d5c216f6f97aeb8d79be0011b06 /src/auditor
parent4a06d7550a6c3911528ff5571b0714b216441388 (diff)
prepare scripts for revocation testing
Diffstat (limited to 'src/auditor')
-rw-r--r--src/auditor/Makefile.am11
-rw-r--r--src/auditor/generate-auditor-basedb.conf1
-rwxr-xr-xsrc/auditor/generate-revoke-basedb.sh295
-rwxr-xr-xsrc/auditor/test-revocation.sh625
4 files changed, 700 insertions, 232 deletions
diff --git a/src/auditor/Makefile.am b/src/auditor/Makefile.am
index 70f364580..dbf982d10 100644
--- a/src/auditor/Makefile.am
+++ b/src/auditor/Makefile.am
@@ -169,7 +169,8 @@ taler_auditor_exchange_LDADD = \
-lgnunetutil $(XLIB)
check_SCRIPTS = \
- test-auditor.sh
+ test-auditor.sh \
+ test-revocation.sh
TESTS = $(check_SCRIPTS)
@@ -177,9 +178,15 @@ EXTRA_DIST = \
auditor.conf \
test-auditor.conf \
generate-auditor-basedb.sh \
+ generate-revoke-basedb.sh \
generate-auditor-basedb.conf \
generate-auditor-basedb-template.conf \
$(check_SCRIPTS) \
+ auditor-basedb.age \
auditor-basedb.sql \
auditor-basedb.fees \
- auditor-basedb.mpub
+ auditor-basedb.mpub \
+ revoke-basedb.age \
+ revoke-basedb.sql \
+ revoke-basedb.fees \
+ revoke-basedb.mpub
diff --git a/src/auditor/generate-auditor-basedb.conf b/src/auditor/generate-auditor-basedb.conf
index a9ee5d891..50b2a1529 100644
--- a/src/auditor/generate-auditor-basedb.conf
+++ b/src/auditor/generate-auditor-basedb.conf
@@ -45,6 +45,7 @@ UNIXPATH = ${TALER_RUNTIME_DIR}/exchange.http
UNIXPATH_MODE = 660
PORT = 8083
AUDITOR_URL = http://localhost:8083/
+TINY_AMOUNT = TESTKUDOS:0.01
[PATHS]
TALER_HOME = ${PWD}/generate_auditordb_home/
diff --git a/src/auditor/generate-revoke-basedb.sh b/src/auditor/generate-revoke-basedb.sh
new file mode 100755
index 000000000..e0e28f15f
--- /dev/null
+++ b/src/auditor/generate-revoke-basedb.sh
@@ -0,0 +1,295 @@
+#!/bin/bash
+# Script to test revocation.
+#
+# Requires the wallet CLI to be installed and in the path. Furthermore, the
+# user running this script must be Postgres superuser and be allowed to
+# create/drop databases.
+#
+set -eu
+
+# Exit, with status code "skip" (no 'real' failure)
+function exit_skip() {
+ echo $1
+ exit 77
+}
+
+# Where do we write the result?
+export BASEDB=${1:-"revoke-basedb"}
+
+# Name of the Postgres database we will use for the script.
+# Will be dropped, do NOT use anything that might be used
+# elsewhere
+export TARGET_DB=taler-auditor-revokedb
+TMP_DIR=`mktemp -d revocation-tmp-XXXXXX`
+export WALLET_DB=wallet-revocation.json
+rm -f $WALLET_DB
+
+# Configuation file will be edited, so we create one
+# from the template.
+export CONF=generate-auditor-basedb-revocation.conf
+cp generate-auditor-basedb-template.conf $CONF
+
+
+echo -n "Testing for taler-bank-manage"
+taler-bank-manage -h >/dev/null </dev/null || exit_skip " MISSING"
+echo " FOUND"
+echo -n "Testing for taler-wallet-cli"
+taler-wallet-cli -v >/dev/null </dev/null || exit_skip " MISSING"
+echo " FOUND"
+
+
+
+# Clean up
+DATA_DIR=`taler-config -f -c $CONF -s PATHS -o TALER_HOME`
+rm -rf $DATA_DIR || true
+
+# reset database
+dropdb $TARGET_DB >/dev/null 2>/dev/null || true
+createdb $TARGET_DB || exit_skip "Could not create database $TARGET_DB"
+
+# obtain key configuration data
+MASTER_PRIV_FILE=`taler-config -f -c $CONF -s EXCHANGE -o MASTER_PRIV_FILE`
+MASTER_PRIV_DIR=`dirname $MASTER_PRIV_FILE`
+mkdir -p $MASTER_PRIV_DIR
+gnunet-ecc -g1 $MASTER_PRIV_FILE > /dev/null
+export MASTER_PUB=`gnunet-ecc -p $MASTER_PRIV_FILE`
+export EXCHANGE_URL=`taler-config -c $CONF -s EXCHANGE -o BASE_URL`
+MERCHANT_PORT=`taler-config -c $CONF -s MERCHANT -o PORT`
+export MERCHANT_URL=http://localhost:${MERCHANT_PORT}/
+BANK_PORT=`taler-config -c $CONF -s BANK -o HTTP_PORT`
+export BANK_URL=http://localhost:${BANK_PORT}/
+export AUDITOR_URL=http://localhost:8083/
+
+# patch configuration
+taler-config -c $CONF -s exchange -o MASTER_PUBLIC_KEY -V $MASTER_PUB
+taler-config -c $CONF -s merchant-exchange-default -o MASTER_KEY -V $MASTER_PUB
+taler-config -c $CONF -s exchangedb-postgres -o CONFIG -V postgres:///$TARGET_DB
+taler-config -c $CONF -s auditordb-postgres -o CONFIG -V postgres:///$TARGET_DB
+taler-config -c $CONF -s merchantdb-postgres -o CONFIG -V postgres:///$TARGET_DB
+taler-config -c $CONF -s bank -o database -V postgres:///$TARGET_DB
+taler-config -c $CONF -s exchange -o KEYDIR -V "${TMP_DIR}/keydir/"
+taler-config -c $CONF -s exchange -o REVOCATION_DIR -V "${TMP_DIR}/revdir/"
+
+# setup exchange
+echo "Setting up exchange"
+taler-exchange-dbinit -c $CONF
+taler-exchange-wire -c $CONF 2> taler-exchange-wire.log
+taler-exchange-keyup -L INFO -c $CONF -o e2a.dat 2> taler-exchange-keyup.log
+
+# setup auditor
+echo "Setting up auditor"
+taler-auditor-dbinit -c $CONF
+taler-auditor-exchange -c $CONF -m $MASTER_PUB -u $EXCHANGE_URL
+taler-auditor-sign -c $CONF -u $AUDITOR_URL -r e2a.dat -o a2e.dat -m $MASTER_PUB
+rm -f e2a.dat
+
+# provide auditor's signature to exchange
+ABD=`taler-config -c $CONF -s EXCHANGEDB -o AUDITOR_BASE_DIR -f`
+mkdir -p $ABD
+mv a2e.dat $ABD
+
+# Launch services
+echo "Launching services"
+taler-bank-manage-testing $CONF postgres:///$TARGET_DB serve-http &> revocation-bank.log &
+taler-exchange-httpd -c $CONF 2> taler-exchange-httpd.log &
+EXCHANGE_PID=$!
+taler-merchant-httpd -c $CONF -L INFO 2> taler-merchant-httpd.log &
+taler-exchange-wirewatch -c $CONF 2> taler-exchange-wirewatch.log &
+taler-auditor-httpd -c $CONF 2> taler-auditor-httpd.log &
+
+# Wait for all bank to be available (usually the slowest)
+for n in `seq 1 50`
+do
+ echo -n "."
+ sleep 0.2
+ OK=0
+ # bank
+ wget http://localhost:8082/ -o /dev/null -O /dev/null >/dev/null || continue
+ OK=1
+ break
+done
+# Wait for all other services to be available
+for n in `seq 1 50`
+do
+ echo -n "."
+ sleep 0.1
+ OK=0
+ # exchange
+ wget http://localhost:8081/ -o /dev/null -O /dev/null >/dev/null || continue
+ # merchant
+ wget http://localhost:9966/ -o /dev/null -O /dev/null >/dev/null || continue
+ # Auditor
+ wget http://localhost:8083/ -o /dev/null -O /dev/null >/dev/null || continue
+ OK=1
+ break
+done
+
+
+if [ 1 != $OK ]
+then
+ kill `jobs -p`
+ wait
+ exit_skip "Failed to launch services"
+fi
+echo " DONE"
+
+# run wallet CLI
+echo "Running wallet"
+taler-wallet-cli --wallet-db=$WALLET_DB --no-throttle \
+ testing withdraw \
+ -e $EXCHANGE_URL \
+ -b $BANK_URL \
+ -a TESTKUDOS:8
+
+
+export coins=$(taler-wallet-cli --wallet-db=$WALLET_DB advanced dump-coins)
+
+# Find coin we want to revoke
+export rc=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:2"))][0] | .coin_pub')
+# Find the denom
+export rd=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:2"))][0] | .denom_pub_hash')
+echo "Revoking denomination ${rd} (to affect coin ${rc})"
+# Find all other coins, which will be suspended
+export susp=$(echo "$coins" | jq --arg rc "$rc" '[.coins[] | select(.coin_pub != $rc) | .coin_pub]')
+
+# Do the revocation
+taler-exchange-keyup -c $CONF -r $rd
+
+# Restart the exchange...
+kill -SIGUSR1 $EXCHANGE_PID
+sleep 1 # Give exchange time to re-scan data
+echo "Restarted the exchange post revocation"
+
+# Now we suspend the other coins, so later we will pay with the recouped coin
+taler-wallet-cli --wallet-db=$WALLET_DB advanced suspend-coins "$susp"
+
+# Update exchange /keys so recoup gets scheduled
+taler-wallet-cli --wallet-db=$WALLET_DB exchanges update \
+ -f $EXCHANGE_URL
+
+# Block until scheduled operations are done
+taler-wallet-cli --wallet-db=$WALLET_DB run-until-done
+
+# Now we buy something, only the coins resulting from recouped will be
+# used, as other ones are suspended
+taler-wallet-cli --wallet-db=$WALLET_DB testing test-pay \
+ -m $MERCHANT_URL -k sandbox \
+ -a "TESTKUDOS:1" -s "foo"
+taler-wallet-cli --wallet-db=$WALLET_DB run-until-done
+
+echo "Purchase with recoup'ed coin (via reserve) done"
+
+# Find coin we want to refresh, then revoke
+export rrc=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:5"))][0] | .coin_pub')
+# Find the denom
+export zombie_denom=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:5"))][0] | .denom_pub_hash')
+
+echo "Will refresh coin ${rrc} of denomination ${zombie_denom}"
+# Find all other coins, which will be suspended
+export susp=$(echo "$coins" | jq --arg rrc "$rrc" '[.coins[] | select(.coin_pub != $rrc) | .coin_pub]')
+
+export rrc
+export zombie_denom
+
+# Travel into the future! (must match DURATION_WITHDRAW option)
+export TIMETRAVEL="--timetravel=604800000000"
+
+echo "Launching exchange 1 week in the future"
+kill -TERM $EXCHANGE_PID
+taler-exchange-httpd $TIMETRAVEL -c $CONF 2> taler-exchange-httpd.log &
+export EXCHANGE_PID=$!
+
+# Wait for exchange to be available
+for n in `seq 1 50`
+do
+ echo -n "."
+ sleep 0.1
+ OK=0
+ # exchange
+ wget http://localhost:8081/ -o /dev/null -O /dev/null >/dev/null || continue
+ OK=1
+ break
+done
+
+echo "Refreshing coin $rrc"
+taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB advanced force-refresh "$rrc"
+taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB run-until-done
+
+# Update our list of the coins
+export coins=$(taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB advanced dump-coins)
+
+# Find resulting refreshed coin
+export freshc=$(echo "$coins" | jq -r --arg rrc "$rrc" '[.coins[] | select((.refresh_parent_coin_pub == $rrc))][0] | .coin_pub')
+
+# Find the denom of freshc
+export fresh_denom=$(echo "$coins" | jq -r --arg rrc "$rrc" '[.coins[] | select((.refresh_parent_coin_pub == $rrc))][0] | .denom_pub_hash')
+
+echo "Coin ${freshc} of denomination ${fresh_denom} is the result of the refresh"
+
+# Find all other coins, which will be suspended
+export susp=$(echo "$coins" | jq --arg freshc "$freshc" '[.coins[] | select(.coin_pub != $freshc) | .coin_pub]')
+
+
+# Do the revocation of freshc
+echo "Revoking ${fresh_denom} (to affect coin ${freshc})"
+taler-exchange-keyup -c $CONF -r $fresh_denom
+
+# Restart the exchange...
+kill -SIGUSR1 $EXCHANGE_PID
+sleep 1 # give exchange time to re-scan data
+
+
+# Now we suspend the other coins, so later we will pay with the recouped coin
+taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB advanced suspend-coins "$susp"
+
+# Update exchange /keys so recoup gets scheduled
+taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB exchanges update \
+ -f $EXCHANGE_URL
+
+# FIXME: wallet is broken...
+echo "Before Wallet CABOOM (type exit, note that you will have to terminate the wallet with CTRL-C)"
+bash
+
+# Block until scheduled operations are done
+taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB run-until-done &> wallet-caboom.log
+
+bash
+# FIXME: check commands work from here...
+
+# Now we buy something, only the coins resulting from recoup+refresh will be
+# used, as other ones are suspended
+taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB testing test-pay \
+ -m $MERCHANT_URL -k sandbox \
+ -a "TESTKUDOS:0.02" -s "bar"
+taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB run-until-done
+
+echo "Bought something with refresh-recouped coin"
+
+echo "Shutting down services"
+kill `jobs -p`
+wait
+
+
+# Dump database
+echo "Dumping database"
+pg_dump -O $TARGET_DB | sed -e '/AS integer/d' > ${BASEDB}.sql
+
+echo $MASTER_PUB > ${BASEDB}.mpub
+
+WIRE_FEE_DIR=`taler-config -c $CONF -f -s exchangedb -o WIREFEE_BASE_DIR`
+cp $WIRE_FEE_DIR/x-taler-bank.fee ${BASEDB}.fees
+date +%s > ${BASEDB}.age
+
+
+# clean up
+echo "Final clean up (disabled)"
+dropdb $TARGET_DB
+rm -r $DATA_DIR || true
+rm $CONF
+rm -r $TMP_DIR
+
+echo "====================================="
+echo " Finished revocation DB generation "
+echo "====================================="
+
+exit 0
diff --git a/src/auditor/test-revocation.sh b/src/auditor/test-revocation.sh
index 52e11a58c..7f9412af7 100755
--- a/src/auditor/test-revocation.sh
+++ b/src/auditor/test-revocation.sh
@@ -1,284 +1,449 @@
#!/bin/bash
-# Script to test revocation.
+# Setup database which was generated from a exchange-wallet interaction
+# with revocations and run the auditor against it.
#
-# Requires the wallet CLI to be installed and in the path. Furthermore, the
-# user running this script must be Postgres superuser and be allowed to
-# create/drop databases.
+# Check that the auditor report is as expected.
#
+# Requires 'jq' tool and Postgres superuser rights!
set -eu
+# Set of numbers for all the testcases.
+# When adding new tests, increase the last number:
+ALL_TESTS=`seq 0 1`
+
+# $TESTS determines which tests we should run.
+# This construction is used to make it easy to
+# only run a subset of the tests. To only run a subset,
+# pass the numbers of the tests to run as the FIRST
+# argument to test-auditor.sh, i.e.:
+#
+# $ test-revocation.sh "1 3"
+#
+# to run tests 1 and 3 only. By default, all tests are run.
+#
+TESTS=${1:-$ALL_TESTS}
+
+# Global variable to run the auditor processes under valgrind
+# VALGRIND=valgrind
+VALGRIND=""
+
# Exit, with status code "skip" (no 'real' failure)
function exit_skip() {
echo $1
exit 77
}
-# Where do we write the result?
-export BASEDB=${1:-"revoke-basedb"}
-
-# Name of the Postgres database we will use for the script.
-# Will be dropped, do NOT use anything that might be used
-# elsewhere
-export TARGET_DB=taler-auditor-revokedb
-TMP_DIR=`mktemp -d revocation-tmp-XXXXXX`
-export WALLET_DB=wallet-revocation.json
-rm -f $WALLET_DB
-
-# Configuation file will be edited, so we create one
-# from the template.
-export CONF=generate-auditor-basedb-revocation.conf
-cp generate-auditor-basedb-template.conf $CONF
-
-
-echo -n "Testing for taler-bank-manage"
-taler-bank-manage -h >/dev/null </dev/null || exit_skip " MISSING"
-echo " FOUND"
-echo -n "Testing for taler-wallet-cli"
-taler-wallet-cli -v >/dev/null </dev/null || exit_skip " MISSING"
-echo " FOUND"
-
-
-
-# Clean up
-DATA_DIR=`taler-config -f -c $CONF -s PATHS -o TALER_HOME`
-rm -rf $DATA_DIR || true
-
-# reset database
-dropdb $TARGET_DB >/dev/null 2>/dev/null || true
-createdb $TARGET_DB || exit_skip "Could not create database $TARGET_DB"
-
-# obtain key configuration data
-MASTER_PRIV_FILE=`taler-config -f -c $CONF -s EXCHANGE -o MASTER_PRIV_FILE`
-MASTER_PRIV_DIR=`dirname $MASTER_PRIV_FILE`
-mkdir -p $MASTER_PRIV_DIR
-gnunet-ecc -g1 $MASTER_PRIV_FILE > /dev/null
-export MASTER_PUB=`gnunet-ecc -p $MASTER_PRIV_FILE`
-export EXCHANGE_URL=`taler-config -c $CONF -s EXCHANGE -o BASE_URL`
-MERCHANT_PORT=`taler-config -c $CONF -s MERCHANT -o PORT`
-export MERCHANT_URL=http://localhost:${MERCHANT_PORT}/
-BANK_PORT=`taler-config -c $CONF -s BANK -o HTTP_PORT`
-export BANK_URL=http://localhost:${BANK_PORT}/
-export AUDITOR_URL=http://localhost:8083/
-
-# patch configuration
-taler-config -c $CONF -s exchange -o MASTER_PUBLIC_KEY -V $MASTER_PUB
-taler-config -c $CONF -s merchant-exchange-default -o MASTER_KEY -V $MASTER_PUB
-taler-config -c $CONF -s exchangedb-postgres -o CONFIG -V postgres:///$TARGET_DB
-taler-config -c $CONF -s auditordb-postgres -o CONFIG -V postgres:///$TARGET_DB
-taler-config -c $CONF -s merchantdb-postgres -o CONFIG -V postgres:///$TARGET_DB
-taler-config -c $CONF -s bank -o database -V postgres:///$TARGET_DB
-taler-config -c $CONF -s exchange -o KEYDIR -V "${TMP_DIR}/keydir/"
-taler-config -c $CONF -s exchange -o REVOCATION_DIR -V "${TMP_DIR}/revdir/"
-
-# setup exchange
-echo "Setting up exchange"
-taler-exchange-dbinit -c $CONF
-taler-exchange-wire -c $CONF 2> taler-exchange-wire.log
-taler-exchange-keyup -L INFO -c $CONF -o e2a.dat 2> taler-exchange-keyup.log
-
-# setup auditor
-echo "Setting up auditor"
-taler-auditor-dbinit -c $CONF
-taler-auditor-exchange -c $CONF -m $MASTER_PUB -u $EXCHANGE_URL
-taler-auditor-sign -c $CONF -u $AUDITOR_URL -r e2a.dat -o a2e.dat -m $MASTER_PUB
-rm -f e2a.dat
-
-# provide auditor's signature to exchange
-ABD=`taler-config -c $CONF -s EXCHANGEDB -o AUDITOR_BASE_DIR -f`
-mkdir -p $ABD
-mv a2e.dat $ABD
-
-# Launch services
-echo "Launching services"
-taler-bank-manage-testing $CONF postgres:///$TARGET_DB serve-http &> revocation-bank.log &
-taler-exchange-httpd -c $CONF 2> taler-exchange-httpd.log &
-EXCHANGE_PID=$!
-taler-merchant-httpd -c $CONF -L INFO 2> taler-merchant-httpd.log &
-taler-exchange-wirewatch -c $CONF 2> taler-exchange-wirewatch.log &
-taler-auditor-httpd -c $CONF 2> taler-auditor-httpd.log &
-
-# Wait for all bank to be available (usually the slowest)
-for n in `seq 1 50`
-do
+# Exit, with error message (hard failure)
+function exit_fail() {
+ echo $1
+ kill `jobs -p` >/dev/null 2>/dev/null || true
+ wait
+ exit 1
+}
+
+
+# Operations to run before the actual audit
+function pre_audit () {
+ # Launch bank
+ echo -n "Launching bank "
+ taler-bank-manage-testing $CONF postgres:///$DB serve-http 2>bank.err >bank.log &
+ for n in `seq 1 20`
+ do
+ echo -n "."
+ sleep 0.1
+ OK=1
+ wget http://localhost:8082/ -o /dev/null -O /dev/null >/dev/null && break
+ OK=0
+ done
+ if [ 1 != $OK ]
+ then
+ exit_skip "Failed to launch bank"
+ fi
+ echo " DONE"
+
+ if test ${1:-no} = "aggregator"
+ then
+ echo -n "Running exchange aggregator ..."
+ taler-exchange-aggregator -L INFO -t -c $CONF 2> aggregator.log || exit_fail "FAIL"
+ echo " DONE"
+ echo -n "Running exchange closer ..."
+ taler-exchange-closer -L INFO -t -c $CONF 2> closer.log || exit_fail "FAIL"
+ echo " DONE"
+ echo -n "Running exchange transfer ..."
+ taler-exchange-transfer -L INFO -t -c $CONF 2> transfer.log || exit_fail "FAIL"
+ echo " DONE"
+ fi
+}
+
+# actual audit run
+function audit_only () {
+ # Run the auditor!
+ echo -n "Running audit(s) ..."
+
+ # Restart so that first run is always fresh, and second one is incremental
+ taler-auditor-dbinit -r -c $CONF
+ $VALGRIND taler-helper-auditor-aggregation -L DEBUG -c $CONF -m $MASTER_PUB > test-audit-aggregation.json 2> test-audit-aggregation.log || exit_fail "aggregation audit failed"
echo -n "."
- sleep 0.2
- OK=0
- # bank
- wget http://localhost:8082/ -o /dev/null -O /dev/null >/dev/null || continue
- OK=1
- break
-done
-# Wait for all other services to be available
-for n in `seq 1 50`
-do
+ $VALGRIND taler-helper-auditor-aggregation -L DEBUG -c $CONF -m $MASTER_PUB > test-audit-aggregation-inc.json 2> test-audit-aggregation-inc.log || exit_fail "incremental aggregation audit failed"
echo -n "."
- sleep 0.1
- OK=0
- # exchange
- wget http://localhost:8081/ -o /dev/null -O /dev/null >/dev/null || continue
- # merchant
- wget http://localhost:9966/ -o /dev/null -O /dev/null >/dev/null || continue
- # Auditor
- wget http://localhost:8083/ -o /dev/null -O /dev/null >/dev/null || continue
- OK=1
- break
-done
-
-
-if [ 1 != $OK ]
-then
- kill `jobs -p`
+ $VALGRIND taler-helper-auditor-coins -L DEBUG -c $CONF -m $MASTER_PUB > test-audit-coins.json 2> test-audit-coins.log || exit_fail "coin audit failed"
+ echo -n "."
+ $VALGRIND taler-helper-auditor-coins -L DEBUG -c $CONF -m $MASTER_PUB > test-audit-coins-inc.json 2> test-audit-coins-inc.log || exit_fail "incremental coin audit failed"
+ echo -n "."
+ $VALGRIND taler-helper-auditor-deposits -L DEBUG -c $CONF -m $MASTER_PUB > test-audit-deposits.json 2> test-audit-deposits.log || exit_fail "deposits audit failed"
+ echo -n "."
+ $VALGRIND taler-helper-auditor-deposits -L DEBUG -c $CONF -m $MASTER_PUB > test-audit-deposits-inc.json 2> test-audit-deposits-inc.log || exit_fail "incremental deposits audit failed"
+ echo -n "."
+ $VALGRIND taler-helper-auditor-reserves -L DEBUG -c $CONF -m $MASTER_PUB > test-audit-reserves.json 2> test-audit-reserves.log || exit_fail "reserves audit failed"
+ echo -n "."
+ $VALGRIND taler-helper-auditor-reserves -L DEBUG -c $CONF -m $MASTER_PUB > test-audit-reserves-inc.json 2> test-audit-reserves-inc.log || exit_fail "incremental reserves audit failed"
+ echo -n "."
+ $VALGRIND taler-helper-auditor-wire -L DEBUG -c $CONF -m $MASTER_PUB > test-audit-wire.json 2> test-wire-audit.log || exit_fail "wire audit failed"
+ echo -n "."
+ $VALGRIND taler-helper-auditor-wire -L DEBUG -c $CONF -m $MASTER_PUB > test-audit-wire-inc.json 2> test-wire-audit-inc.log || exit_fail "wire audit failed"
+ echo -n "."
+
+ echo " DONE"
+}
+
+
+# Cleanup to run after the auditor
+function post_audit () {
+ kill -TERM `jobs -p` >/dev/null 2>/dev/null || true
+ echo -n "Waiting for servers to die ..."
wait
- exit_skip "Failed to launch services"
-fi
-echo " DONE"
+ echo "DONE"
+ echo -n "TeXing ."
+ taler-helper-auditor-render.py test-audit-aggregation.json test-audit-coins.json test-audit-deposits.json test-audit-reserves.json test-audit-wire.json < ../../contrib/auditor-report.tex.j2 > test-report.tex || exit_fail "Renderer failed"
-# run wallet CLI
-echo "Running wallet"
-taler-wallet-cli --wallet-db=$WALLET_DB --no-throttle \
- testing withdraw \
- -e $EXCHANGE_URL \
- -b $BANK_URL \
- -a TESTKUDOS:8
+ echo -n "."
+ timeout 10 pdflatex test-report.tex >/dev/null || exit_fail "pdflatex failed"
+ echo -n "."
+ timeout 10 pdflatex test-report.tex >/dev/null
+ echo " DONE"
+}
-export coins=$(taler-wallet-cli --wallet-db=$WALLET_DB advanced dump-coins)
+# Run audit process on current database, including report
+# generation. Pass "aggregator" as $1 to run
+# $ taler-exchange-aggregator
+# before auditor (to trigger pending wire transfers).
+function run_audit () {
+ pre_audit ${1:-no}
+ audit_only
+ post_audit
-# Find coin we want to revoke
-export rc=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:2"))][0] | .coin_pub')
-# Find the denom
-export rd=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:2"))][0] | .denom_pub_hash')
-echo "Revoking denomination ${rd} (to affect coin ${rc})"
-# Find all other coins, which will be suspended
-export susp=$(echo "$coins" | jq --arg rc "$rc" '[.coins[] | select(.coin_pub != $rc) | .coin_pub]')
+}
-# Do the revocation
-taler-exchange-keyup -c $CONF -r $rd
-# Restart the exchange...
-kill -SIGUSR1 $EXCHANGE_PID
-sleep 1 # Give exchange time to re-scan data
-echo "Restarted the exchange post revocation"
+# Do a full reload of the (original) database
+full_reload()
+{
+ echo -n "Doing full reload of the database... "
+ dropdb $DB 2> /dev/null || true
+ createdb -T template0 $DB || exit_skip "could not create database"
+ # Import pre-generated database, -q(ietly) using single (-1) transaction
+ psql -Aqt $DB -q -1 -f ${BASEDB}.sql > /dev/null || exit_skip "Failed to load database"
+ echo "DONE"
+}
+
+
+function test_0() {
+
+echo "===========0: normal run with aggregator==========="
+run_audit aggregator
+
+echo "Checking output"
+# if an emergency was detected, that is a bug and we should fail
+echo -n "Test for emergencies... "
+jq -e .emergencies[0] < test-audit-coins.json > /dev/null && exit_fail "Unexpected emergency detected in ordinary run" || echo PASS
+echo -n "Test for deposit confirmation emergencies... "
+jq -e .deposit_confirmation_inconsistencies[0] < test-audit-deposits.json > /dev/null && exit_fail "Unexpected deposit confirmation inconsistency detected" || echo PASS
+echo -n "Test for emergencies by count... "
+jq -e .emergencies_by_count[0] < test-audit-coins.json > /dev/null && exit_fail "Unexpected emergency by count detected in ordinary run" || echo PASS
-# Now we suspend the other coins, so later we will pay with the recouped coin
-taler-wallet-cli --wallet-db=$WALLET_DB advanced suspend-coins "$susp"
+echo -n "Test for wire inconsistencies... "
+jq -e .wire_out_amount_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected wire out inconsistency detected in ordinary run"
+jq -e .reserve_in_amount_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected reserve in inconsistency detected in ordinary run"
+jq -e .missattribution_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected missattribution inconsistency detected in ordinary run"
+jq -e .row_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected row inconsistency detected in ordinary run"
+jq -e .denomination_key_validity_withdraw_inconsistencies[0] < test-audit-reserves.json > /dev/null && exit_fail "Unexpected denomination key withdraw inconsistency detected in ordinary run"
+jq -e .row_minor_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected minor row inconsistency detected in ordinary run"
+jq -e .lag_details[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected lag detected in ordinary run"
+jq -e .wire_format_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected wire format inconsistencies detected in ordinary run"
-# Update exchange /keys so recoup gets scheduled
-taler-wallet-cli --wallet-db=$WALLET_DB exchanges update \
- -f $EXCHANGE_URL
-# Block until scheduled operations are done
-taler-wallet-cli --wallet-db=$WALLET_DB run-until-done
+# TODO: check operation balances are correct (once we have all transaction types and wallet is deterministic)
+# TODO: check revenue summaries are correct (once we have all transaction types and wallet is deterministic)
-# Now we buy something, only the coins resulting from recouped will be
-# used, as other ones are suspended
-taler-wallet-cli --wallet-db=$WALLET_DB testing test-pay \
- -m $MERCHANT_URL -k sandbox \
- -a "TESTKUDOS:1" -s "foo"
-taler-wallet-cli --wallet-db=$WALLET_DB run-until-done
+echo PASS
+
+LOSS=`jq -r .total_bad_sig_loss < test-audit-aggregation.json`
+if test $LOSS != "TESTKUDOS:0"
+then
+ exit_fail "Wrong total bad sig loss from aggregation, got unexpected loss of $LOSS"
+fi
+LOSS=`jq -r .total_bad_sig_loss < test-audit-coins.json`
+if test $LOSS != "TESTKUDOS:0"
+then
+ exit_fail "Wrong total bad sig loss from coins, got unexpected loss of $LOSS"
+fi
+LOSS=`jq -r .total_bad_sig_loss < test-audit-reserves.json`
+if test $LOSS != "TESTKUDOS:0"
+then
+ exit_fail "Wrong total bad sig loss from reserves, got unexpected loss of $LOSS"
+fi
-echo "Purchase with recoup'ed coin (via reserve) done"
+echo -n "Test for wire amounts... "
+WIRED=`jq -r .total_wire_in_delta_plus < test-audit-wire.json`
+if test $WIRED != "TESTKUDOS:0"
+then
+ exit_fail "Expected total wire delta plus wrong, got $WIRED"
+fi
+WIRED=`jq -r .total_wire_in_delta_minus < test-audit-wire.json`
+if test $WIRED != "TESTKUDOS:0"
+then
+ exit_fail "Expected total wire delta minus wrong, got $WIRED"
+fi
+WIRED=`jq -r .total_wire_out_delta_plus < test-audit-wire.json`
+if test $WIRED != "TESTKUDOS:0"
+then
+ exit_fail "Expected total wire delta plus wrong, got $WIRED"
+fi
+WIRED=`jq -r .total_wire_out_delta_minus < test-audit-wire.json`
+if test $WIRED != "TESTKUDOS:0"
+then
+ exit_fail "Expected total wire delta minus wrong, got $WIRED"
+fi
+WIRED=`jq -r .total_missattribution_in < test-audit-wire.json`
+if test $WIRED != "TESTKUDOS:0"
+then
+ exit_fail "Expected total missattribution in wrong, got $WIRED"
+fi
+echo PASS
-# Find coin we want to refresh, then revoke
-export rrc=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:5"))][0] | .coin_pub')
-# Find the denom
-export zombie_denom=$(echo "$coins" | jq -r '[.coins[] | select((.denom_value == "TESTKUDOS:5"))][0] | .denom_pub_hash')
+echo -n "Checking for unexpected arithmetic differences "
+LOSS=`jq -r .total_arithmetic_delta_plus < test-audit-aggregation.json`
+if test $LOSS != "TESTKUDOS:0"
+then
+ exit_fail "Wrong arithmetic delta from aggregations, got unexpected plus of $LOSS"
+fi
+LOSS=`jq -r .total_arithmetic_delta_minus < test-audit-aggregation.json`
+if test $LOSS != "TESTKUDOS:0"
+then
+ exit_fail "Wrong arithmetic delta from aggregation, got unexpected minus of $LOSS"
+fi
+LOSS=`jq -r .total_arithmetic_delta_plus < test-audit-coins.json`
+if test $LOSS != "TESTKUDOS:0"
+then
+ exit_fail "Wrong arithmetic delta from coins, got unexpected plus of $LOSS"
+fi
+LOSS=`jq -r .total_arithmetic_delta_minus < test-audit-coins.json`
+if test $LOSS != "TESTKUDOS:0"
+then
+ exit_fail "Wrong arithmetic delta from coins, got unexpected minus of $LOSS"
+fi
+LOSS=`jq -r .total_arithmetic_delta_plus < test-audit-reserves.json`
+if test $LOSS != "TESTKUDOS:0"
+then
+ exit_fail "Wrong arithmetic delta from reserves, got unexpected plus of $LOSS"
+fi
+LOSS=`jq -r .total_arithmetic_delta_minus < test-audit-reserves.json`
+if test $LOSS != "TESTKUDOS:0"
+then
+ exit_fail "Wrong arithmetic delta from reserves, got unexpected minus of $LOSS"
+fi
-echo "Will refresh coin ${rrc} of denomination ${zombie_denom}"
-# Find all other coins, which will be suspended
-export susp=$(echo "$coins" | jq --arg rrc "$rrc" '[.coins[] | select(.coin_pub != $rrc) | .coin_pub]')
+jq -e .amount_arithmetic_inconsistencies[0] < test-audit-aggregation.json > /dev/null && exit_fail "Unexpected arithmetic inconsistencies from aggregations detected in ordinary run"
+jq -e .amount_arithmetic_inconsistencies[0] < test-audit-coins.json > /dev/null && exit_fail "Unexpected arithmetic inconsistencies from coins detected in ordinary run"
+jq -e .amount_arithmetic_inconsistencies[0] < test-audit-reserves.json > /dev/null && exit_fail "Unexpected arithmetic inconsistencies from reserves detected in ordinary run"
+echo PASS
-export rrc
-export zombie_denom
+echo -n "Checking for unexpected wire out differences "
+jq -e .wire_out_inconsistencies[0] < test-audit-aggregation.json > /dev/null && exit_fail "Unexpected wire out inconsistencies detected in ordinary run"
+echo PASS
-# Travel into the future! (must match DURATION_WITHDRAW option)
-export TIMETRAVEL="--timetravel=604800000000"
+# cannot easily undo aggregator, hence full reload
+full_reload
-echo "Launching exchange 1 week in the future"
-kill -TERM $EXCHANGE_PID
-taler-exchange-httpd $TIMETRAVEL -c $CONF 2> taler-exchange-httpd.log &
-export EXCHANGE_PID=$!
+}
-# Wait for exchange to be available
-for n in `seq 1 50`
-do
- echo -n "."
- sleep 0.1
- OK=0
- # exchange
- wget http://localhost:8081/ -o /dev/null -O /dev/null >/dev/null || continue
- OK=1
- break
-done
-echo "Refreshing coin $rrc"
-taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB advanced force-refresh "$rrc"
-taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB run-until-done
+# Run without aggregator, hence auditor should detect wire
+# transfer lag!
+function test_1() {
-# Update our list of the coins
-export coins=$(taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB advanced dump-coins)
+echo "===========1: normal run==========="
+run_audit
-# Find resulting refreshed coin
-export freshc=$(echo "$coins" | jq -r --arg rrc "$rrc" '[.coins[] | select((.refresh_parent_coin_pub == $rrc))][0] | .coin_pub')
+echo "Checking output"
+# if an emergency was detected, that is a bug and we should fail
+echo -n "Test for emergencies... "
+jq -e .emergencies[0] < test-audit-coins.json > /dev/null && exit_fail "Unexpected emergency detected in ordinary run" || echo PASS
+echo -n "Test for emergencies by count... "
+jq -e .emergencies_by_count[0] < test-audit-coins.json > /dev/null && exit_fail "Unexpected emergency by count detected in ordinary run" || echo PASS
-# Find the denom of freshc
-export fresh_denom=$(echo "$coins" | jq -r --arg rrc "$rrc" '[.coins[] | select((.refresh_parent_coin_pub == $rrc))][0] | .denom_pub_hash')
+echo -n "Test for wire inconsistencies... "
+jq -e .wire_out_amount_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected wire out inconsistency detected in ordinary run"
+jq -e .reserve_in_amount_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected reserve in inconsistency detected in ordinary run"
+jq -e .missattribution_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected missattribution inconsistency detected in ordinary run"
+jq -e .row_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected row inconsistency detected in ordinary run"
+jq -e .row_minor_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected minor row inconsistency detected in ordinary run"
+jq -e .wire_format_inconsistencies[0] < test-audit-wire.json > /dev/null && exit_fail "Unexpected wire format inconsistencies detected in ordinary run"
-echo "Coin ${freshc} of denomination ${fresh_denom} is the result of the refresh"
+# TODO: check operation balances are correct (once we have all transaction types and wallet is deterministic)
+# TODO: check revenue summaries are correct (once we have all transaction types and wallet is deterministic)
-# Find all other coins, which will be suspended
-export susp=$(echo "$coins" | jq --arg freshc "$freshc" '[.coins[] | select(.coin_pub != $freshc) | .coin_pub]')
+echo PASS
+echo -n "Check for lag detection... "
-# Do the revocation of freshc
-echo "Revoking ${fresh_denom} (to affect coin ${freshc})"
-taler-exchange-keyup -c $CONF -r $fresh_denom
+# Check wire transfer lag reported (no aggregator!)
+# NOTE: This test is EXPECTED to fail for ~1h after
+# re-generating the test database as we do not
+# report lag of less than 1h (see GRACE_PERIOD in
+# taler-helper-auditor-wire.c)
+if [ $DATABASE_AGE -gt 3600 ]
+then
+ jq -e .lag_details[0] < test-audit-wire.json > /dev/null || exit_fail "Lag not detected in run without aggregator at age $DELTA"
+
+ LAG=`jq -r .total_amount_lag < test-audit-wire.json`
+ if test $LAG = "TESTKUDOS:0"
+ then
+ exit_fail "Expected total lag to be non-zero"
+ fi
+ echo "PASS"
+else
+ echo "SKIP (database too new)"
+fi
-# Restart the exchange...
-kill -SIGUSR1 $EXCHANGE_PID
-sleep 1 # give exchange time to re-scan data
+echo -n "Test for wire amounts... "
+WIRED=`jq -r .total_wire_in_delta_plus < test-audit-wire.json`
+if test $WIRED != "TESTKUDOS:0"
+then
+ exit_fail "Expected total wire delta plus wrong, got $WIRED"
+fi
+WIRED=`jq -r .total_wire_in_delta_minus < test-audit-wire.json`
+if test $WIRED != "TESTKUDOS:0"
+then
+ exit_fail "Expected total wire delta minus wrong, got $WIRED"
+fi
+WIRED=`jq -r .total_wire_out_delta_plus < test-audit-wire.json`
+if test $WIRED != "TESTKUDOS:0"
+then
+ exit_fail "Expected total wire delta plus wrong, got $WIRED"
+fi
+WIRED=`jq -r .total_wire_out_delta_minus < test-audit-wire.json`
+if test $WIRED != "TESTKUDOS:0"
+then
+ exit_fail "Expected total wire delta minus wrong, got $WIRED"
+fi
+WIRED=`jq -r .total_missattribution_in < test-audit-wire.json`
+if test $WIRED != "TESTKUDOS:0"
+then
+ exit_fail "Expected total missattribution in wrong, got $WIRED"
+fi
+# Database was unmodified, no need to undo
+echo "OK"
+}
-# Now we suspend the other coins, so later we will pay with the recouped coin
-taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB advanced suspend-coins "$susp"
-# Update exchange /keys so recoup gets scheduled
-taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB exchanges update \
- -f $EXCHANGE_URL
-echo "Before Wallet CABOOM (type exit, note that you will have to terminate the wallet with CTRL-C)"
-bash
-# Block until scheduled operations are done
-taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB run-until-done &> wallet-caboom.log
+# *************** Main test loop starts here **************
+
+
+# Run all the tests against the database given in $1.
+# Sets $fail to 0 on success, non-zero on failure.
+check_with_database()
+{
+ BASEDB=$1
+ echo "Running test suite with database $BASEDB using configuration $CONF"
+
+ # Setup database-specific globals
+ MASTER_PUB=`cat ${BASEDB}.mpub`
+
+ # Where to store wire fee details for aggregator
+ echo "Storing wire fees"
+ WIRE_FEE_DIR=`taler-config -c $CONF -f -s exchangedb -o WIREFEE_BASE_DIR`
+ mkdir -p $WIRE_FEE_DIR
+ cp ${BASEDB}.fees $WIRE_FEE_DIR/x-taler-bank.fee
+
+ # Determine database age
+ echo "Calculating database age based on ${BASEDB}.age"
+ AGE=`cat ${BASEDB}.age`
+ NOW=`date +%s`
+ # NOTE: expr "fails" if the result is zero.
+ DATABASE_AGE=`expr ${NOW} - ${AGE} || true`
+ echo "Database age is ${DATABASE_AGE} seconds"
+
+ # Load database
+ full_reload
+
+ # Run test suite
+ fail=0
+ for i in $TESTS
+ do
+ test_$i
+ if test 0 != $fail
+ then
+ break
+ fi
+ done
+ # echo "Cleanup (disabled, leaving database $DB behind)"
+ dropdb $DB
+ rm -r $WIRE_FEE_DIR
+ rm -f test-audit.log test-wire-audit.log
+}
-bash
-# Now we buy something, only the coins resulting from recoup+refresh will be
-# used, as other ones are suspended
-taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB testing test-pay \
- -m $MERCHANT_URL -k sandbox \
- -a "TESTKUDOS:0.02" -s "bar"
-taler-wallet-cli $TIMETRAVEL --wallet-db=$WALLET_DB run-until-done
-echo "Bought something with refresh-recouped coin"
+# *************** Main logic starts here **************
-bash
+# ####### Setup globals ######
+# Postgres database to use (must match test-auditor.conf)
+DB=taler-auditor-test
-echo "Shutting down services"
-kill `jobs -p`
-wait
+# Configuration file to use
+CONF=test-auditor.conf
+# test required commands exist
+echo "Testing for jq"
+jq -h > /dev/null || exit_skip "jq required"
+echo "Testing for taler-bank-manage"
+taler-bank-manage -h >/dev/null </dev/null || exit_skip "taler-bank-manage required"
+echo "Testing for pdflatex"
+which pdflatex > /dev/null </dev/null || exit_skip "pdflatex required"
-# clean up
-echo "Final clean up (disabled)"
-# dropdb $TARGET_DB
-# rm -r $DATA_DIR || true
-# rm $CONF
-# rm -r $TMP_DIR
+# check if we should regenerate the database
+if test -n "${1:-}"
+then
+ echo "Custom run, will only run on existing DB."
+else
+ echo -n "Testing for taler-wallet-cli"
+ if taler-wallet-cli -h >/dev/null </dev/null 2>/dev/null
+ then
+ MYDIR=`mktemp -d /tmp/taler-auditor-basedbXXXXXX`
+ echo " FOUND. Generating fresh database at $MYDIR"
+ if ./generate-revoke-basedb.sh $MYDIR/basedb
+ then
+ check_with_database $MYDIR/basedb
+ if test x$fail != x0
+ then
+ exit $fail
+ else
+ echo "Cleaning up $MYDIR..."
+ rm -rf $MYDIR || echo "Removing $MYDIR failed"
+ fi
+ else
+ echo "Generation failed, running only on existing DB"
+ fi
+ else
+ echo " NOT FOUND, running only on existing DB"
+ fi
+fi
-echo "====================================="
-echo " Finished revocation test"
-echo "====================================="
+check_with_database "revoke-basedb"
-exit 0
+exit $fail