test_prepare.sh (17498B)
1 #!/bin/bash 2 # Shell script to launch Taler components 3 # and Anastasis providers for local test 4 # using TESTKUDOS. 5 6 set -eu 7 8 # Exit, with status code "skip" (no 'real' failure) 9 function exit_skip() { 10 echo " SKIP: $1" 11 exit 77 12 } 13 14 # Exit, with error message (hard failure) 15 function exit_fail() { 16 echo " FAIL: $1" 17 exit 1 18 } 19 20 # Cleanup to run whenever we exit 21 function cleanup() 22 { 23 if test -n "${SETUP_PID:-}" 24 then 25 kill -TERM "$SETUP_PID" 2> /dev/null || true 26 wait "$SETUP_PID" 2> /dev/null || true 27 fi 28 for n in `jobs -p` 29 do 30 kill -SIGCONT $n # in case one provider was suspended 31 kill $n 2> /dev/null || true 32 done 33 rm -rf $CONF $CONF.edited $CONF_4 $CONF_IBAN $WALLET_DB $R1FILE $R2FILE $B1FILE $B2FILE $TMP_DIR 34 wait 35 } 36 37 38 # Launch the GNU Taler services (bank, exchange, merchant) via 39 # taler-unified-setup.sh and return once they are up. Mirrors the setup() 40 # helper of exchange/src/testing/setup.sh; we cannot source that file as it is 41 # not installed. Arguments are passed on to taler-unified-setup.sh. 42 function taler_setup() 43 { 44 local FIFO_DIR 45 local FIFO_OUT 46 47 # Create a named pipe in a temp directory we own. 48 FIFO_DIR=`mktemp -d fifo-XXXXXX` 49 FIFO_OUT="$FIFO_DIR/out" 50 mkfifo "$FIFO_OUT" 51 # Open pipe as FD 3 (RW) and FD 4 (RO) 52 exec 3<> "$FIFO_OUT" 4< "$FIFO_OUT" 53 rm -rf "$FIFO_DIR" 54 # '-W' is required for our termination logic to work. 55 taler-unified-setup.sh -W "$@" >&3 2> taler-unified-setup.log & 56 SETUP_PID=$! 57 exec 3>&- 58 # taler-unified-setup.sh prints "READY:$TESTROOT" once everything is up. 59 # Read until EOF instead of 'sed -u /READY:/ q' so that we can tell "the 60 # system came up" apart from "taler-unified-setup.sh died first". 61 READY=0 62 while IFS= read -r LINE <&4 63 do 64 case "$LINE" in 65 READY:*) 66 READY=1 67 break 68 ;; 69 esac 70 done 71 exec 4>&- 72 if test 1 != $READY 73 then 74 exit_skip "Failed to launch Taler services, see taler-unified-setup.log" 75 fi 76 } 77 78 79 # Create a bank account at libeufin-bank. Prints its payto URI. 80 # $1 = username, $2 = password, $3 = legal name, $4 = payto URI (optional) 81 function make_bank_account() { 82 if test -z "${4:-}" 83 then 84 libeufin-bank create-account \ 85 -c $CONF_IBAN \ 86 -u "$1" -p "$2" --name "$3" 2>> iban-setup.log 87 else 88 libeufin-bank create-account \ 89 -c $CONF_IBAN \ 90 -u "$1" -p "$2" --name "$3" --payto_uri "$4" 2>> iban-setup.log 91 fi 92 } 93 94 95 # Transfer funds from the debit account to the Anastasis account and have 96 # the Anastasis IBAN helper pick the transfer up. 97 # $1 = amount ($CURRENCY:X.Y), $2 = subject. 98 function wire_transfer_to_anastasis() { 99 curl -s -X POST \ 100 --user "${DEBIT_USERNAME}:${DEBIT_PASSWORD}" \ 101 -H "Content-Type: application/json" \ 102 -d "{\"payto_uri\":\"${PAYTO_CREDIT}&message=$(echo "$2" | jq -sRr @uri)&amount=$1\"}" \ 103 "${IBAN_BANK_URL}accounts/${DEBIT_USERNAME}/transactions" > /dev/null 104 anastasis-helper-authorization-iban -c $CONF_4 -t -L INFO 105 } 106 107 108 if test "${1:-}" != "free" -a "${1:-}" != "fees" 109 then 110 echo "Launch script with either 'free' or 'fees' argument to launch providers with/without fees." 111 exit 1 112 fi 113 114 export CONF_1="test_anastasis_reducer_1.conf" 115 export CONF_2="test_anastasis_reducer_2.conf" 116 export CONF_3="test_anastasis_reducer_3.conf" 117 if test $1 = 'free' 118 then 119 CONF4="test_anastasis_reducer_4_free.conf" 120 else 121 CONF4="test_anastasis_reducer_4.conf" 122 fi 123 124 # Taler configuration file will be edited, so we create one 125 # from the template. 126 export CONF=`mktemp test_reducerXXXXXX.conf` 127 export CONF_4=`mktemp test_reducer_4XXXXXX.conf` 128 export CONF_IBAN=`mktemp test_reducer_ibanXXXXXX.conf` 129 cp test_reducer.conf $CONF 130 cp $CONF4 $CONF_4 131 132 TMP_DIR=`mktemp -d keys-tmp-XXXXXX` 133 # wallet-core needs an sqlite3 database; a '.json' name selects the 134 # no-longer-supported in-memory backend. 135 WALLET_DB=`mktemp test_reducer_walletXXXXXX.sqlite3` 136 B1FILE=`mktemp test_reducer_stateB1XXXXXX` 137 B2FILE=`mktemp test_reducer_stateB2XXXXXX` 138 R1FILE=`mktemp test_reducer_stateR1XXXXXX` 139 R2FILE=`mktemp test_reducer_stateR2XXXXXX` 140 IBAN_ACTIVE='false' 141 SETUP_PID='' 142 143 # Install cleanup handler (except for kill -9) 144 trap cleanup EXIT 145 146 # Check we can actually run 147 if test $1 = 'fees' 148 then 149 echo -n "Testing for taler" 150 taler-exchange-httpd -h > /dev/null || exit_skip " taler-exchange required" 151 taler-merchant-httpd -h > /dev/null || exit_skip " taler-merchant required" 152 # note: 'taler-unified-setup.sh -h' exits non-zero (its exit trap wins) 153 command -v taler-unified-setup.sh > /dev/null || exit_skip " taler-unified-setup.sh required" 154 echo " FOUND" 155 156 echo -n "Testing for libeufin-bank" 157 libeufin-bank --help >/dev/null </dev/null || exit_skip " MISSING" 158 echo " FOUND" 159 160 echo -n "Testing for taler-wallet-cli" 161 taler-wallet-cli -v >/dev/null </dev/null || exit_skip " MISSING" 162 echo " FOUND" 163 164 echo -n "Testing for jq" 165 jq --version >/dev/null </dev/null || exit_skip " MISSING" 166 echo " FOUND" 167 fi 168 169 echo -n "Testing for anastasis-httpd" 170 anastasis-httpd -h >/dev/null </dev/null || exit_skip " MISSING" 171 echo " FOUND" 172 173 echo -n "Initialize anastasis database ..." 174 # Name of the Postgres database we will use for the script. 175 # Will be dropped, do NOT use anything that might be used 176 # elsewhere 177 TARGET_DB_1=`anastasis-config -c $CONF_1 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` 178 TARGET_DB_2=`anastasis-config -c $CONF_2 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` 179 TARGET_DB_3=`anastasis-config -c $CONF_3 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` 180 TARGET_DB_4=`anastasis-config -c $CONF_4 -s stasis-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` 181 182 dropdb $TARGET_DB_1 >/dev/null 2>/dev/null || true 183 createdb $TARGET_DB_1 || exit_skip "Could not create database $TARGET_DB_1" 184 anastasis-dbinit -c $CONF_1 2> anastasis-dbinit_1.log 185 dropdb $TARGET_DB_2 >/dev/null 2>/dev/null || true 186 createdb $TARGET_DB_2 || exit_skip "Could not create database $TARGET_DB_2" 187 anastasis-dbinit -c $CONF_2 2> anastasis-dbinit_2.log 188 dropdb $TARGET_DB_3 >/dev/null 2>/dev/null || true 189 createdb $TARGET_DB_3 || exit_skip "Could not create database $TARGET_DB_3" 190 anastasis-dbinit -c $CONF_3 2> anastasis-dbinit_3.log 191 dropdb $TARGET_DB_4 >/dev/null 2>/dev/null || true 192 createdb $TARGET_DB_4 || exit_skip "Could not create database $TARGET_DB_4" 193 anastasis-dbinit -c $CONF_4 2> anastasis-dbinit_4.log 194 195 echo " OK" 196 197 if test $1 = 'fees' 198 then 199 200 echo -n "Setting up Taler databases ..." 201 TALER_DB=talercheck 202 # bank, exchange and merchant share one database here 203 taler-exchange-config -c $CONF -s exchangedb-postgres -o CONFIG -V postgres:///$TALER_DB 204 taler-exchange-config -c $CONF -s merchantdb-postgres -o CONFIG -V postgres:///$TALER_DB 205 taler-exchange-config -c $CONF -s libeufin-bankdb-postgres -o CONFIG -V postgres:///$TALER_DB 206 taler-exchange-config -c $CONF -s exchange -o KEYDIR -V "${TMP_DIR}/keydir/" 207 taler-exchange-config -c $CONF -s exchange -o REVOCATION_DIR -V "${TMP_DIR}/revdir/" 208 DATA_DIR=`taler-exchange-config -f -c $CONF -s PATHS -o TALER_HOME` 209 rm -rf $DATA_DIR 210 dropdb $TALER_DB >/dev/null 2>/dev/null || true 211 createdb $TALER_DB || exit_skip "Could not create database $TALER_DB" 212 echo " OK" 213 214 # taler-unified-setup.sh launches the bank (libeufin-bank), the exchange 215 # (including the secmods and the offline key ceremony) and the merchant 216 # (including taler-merchant-exchangekeyupdate, without which the merchant 217 # never learns the exchange's keys and refuses to create orders). It 218 # writes the configuration it actually uses to "$CONF.edited". 219 echo "Launching Taler services ..." 220 taler_setup -c $CONF -L INFO -b -e -m -w -r merchant-exchange-default 221 echo "Taler services up" 222 223 BANK_PORT=`taler-exchange-config -c $CONF.edited -s libeufin-bank -o PORT` 224 BANK_URL="http://localhost:${BANK_PORT}/" 225 EXCHANGE_URL=`taler-exchange-config -c $CONF.edited -s exchange -o BASE_URL` 226 MERCHANT_PORT=`taler-merchant-config -c $CONF.edited -s merchant -o PORT` 227 MERCHANT_URL="http://localhost:${MERCHANT_PORT}/" 228 229 echo -n "Configuring merchant instance ..." 230 # POST to the merchant and fail loudly if it does not like the request. 231 # $1 = path, $2 = JSON body 232 function merchant_post() { 233 local RESP 234 local CODE 235 236 RESP=`curl -s -w '\n%{http_code}' -H "Content-Type: application/json" \ 237 -X POST -d "$2" "${MERCHANT_URL}$1"` 238 CODE=`echo "$RESP" | tail -n1` 239 case "$CODE" in 240 20*) 241 ;; 242 *) 243 echo " FAILED ($CODE)" 244 echo "$RESP" | head -n-1 245 exit_fail "merchant rejected POST /$1" 246 ;; 247 esac 248 } 249 # The default instance is called "admin" and is served at the root of the 250 # merchant; the historic /instances/default/ prefix is gone. 'use_stefan' 251 # is required by the current merchant protocol. 252 merchant_post management/instances \ 253 '{"auth":{"method":"external"},"id":"admin","name":"default","address":{},"jurisdiction":{},"use_stefan":true,"default_max_wire_fee":"TESTKUDOS:1","default_max_deposit_fee":"TESTKUDOS:1","default_wire_fee_amortization":1,"default_wire_transfer_delay":{"d_us":3600000000},"default_pay_delay":{"d_us":3600000000}}' 254 # 'fortythree' is one of the accounts taler-unified-setup.sh registers 255 merchant_post private/accounts \ 256 '{"payto_uri":"payto://x-taler-bank/localhost/fortythree?receiver-name=Forty+Three"}' 257 echo " OK" 258 259 echo -n "Preparing wallet" 260 rm -f $WALLET_DB 261 taler-wallet-cli --no-throttle --wallet-db=$WALLET_DB api \ 262 --expect-success 'withdrawTestBalance' \ 263 "$(jq -n ' 264 { 265 amount: "TESTKUDOS:100", 266 corebankApiBaseUrl: $BANK_URL, 267 exchangeBaseUrl: $EXCHANGE_URL 268 }' \ 269 --arg BANK_URL "$BANK_URL" \ 270 --arg EXCHANGE_URL "$EXCHANGE_URL" 271 )" 2> wallet-withdraw.log >/dev/null 272 echo -n "." 273 # the wallet's withdrawal only completes once the exchange has seen the 274 # incoming wire transfer 275 taler-exchange-wirewatch -c $CONF.edited -t 2> wirewatch-once.log 276 echo -n "." 277 taler-wallet-cli --wallet-db=$WALLET_DB run-until-done 2> wallet-run.log >/dev/null 278 echo " OK" 279 280 echo -n "Setting up IBAN authentication ..." 281 # The IBAN challenge needs a bank that speaks IBAN and whose incoming 282 # transfers Anastasis can see through the taler-revenue API. That cannot 283 # be the bank the exchange uses: libeufin-bank serves a single WIRE_TYPE, 284 # and the exchange side of this test is x-taler-bank. So we run a second, 285 # IBAN-typed libeufin-bank for this one authorization method -- it also 286 # matches the fact that the IBAN challenge is priced in EUR. 287 IBAN_DB=anastasisibancheck 288 IBAN_BANK_PORT=8092 289 IBAN_BANK_URL="http://localhost:${IBAN_BANK_PORT}/" 290 REASON="" 291 # both IBANs must pass the checksum: libeufin-bank rejects malformed ones 292 IBAN_CREDIT="DE44500105175407324931" 293 IBAN_DEBIT="FR1420041010050500013M02606" 294 PERSON_CREDIT_NAME="Person Credit" 295 CREDIT_USERNAME=anastasis-credit-user 296 CREDIT_PASSWORD=anastasis-credit-password 297 DEBIT_USERNAME=anastasis-debit-user 298 DEBIT_PASSWORD=anastasis-debit-password 299 PAYTO_CREDIT="payto://iban/${IBAN_CREDIT}?receiver-name=Person+Credit" 300 PAYTO_DEBIT="payto://iban/${IBAN_DEBIT}?receiver-name=Person+Debit" 301 IBAN_REVENUE_URL="${IBAN_BANK_URL}accounts/${CREDIT_USERNAME}/taler-revenue/" 302 # the challenge is priced in this currency, e.g. "EUR:1" 303 IBAN_CURRENCY=`anastasis-config -c $CONF_4 -s authorization-iban -o COST | cut -d: -f1` 304 cat > $CONF_IBAN <<EOF 305 # Generated by test_prepare.sh: the "customer's bank" for IBAN challenges. 306 [PATHS] 307 TALER_HOME = \${PWD}/test_reducer_home/ 308 TALER_DATA_HOME = \$TALER_HOME/.local/share/taler/ 309 TALER_CONFIG_HOME = \$TALER_HOME/.config/taler/ 310 TALER_CACHE_HOME = \$TALER_HOME/.cache/taler/ 311 TALER_RUNTIME_DIR = \${TMPDIR:-\${TMP:-/tmp}}/taler-system-runtime-\${USER}/ 312 313 [libeufin-bank] 314 CURRENCY = ${IBAN_CURRENCY} 315 BASE_URL = ${IBAN_BANK_URL} 316 SERVE = tcp 317 PORT = ${IBAN_BANK_PORT} 318 WIRE_TYPE = iban 319 IBAN_PAYTO_BIC = SANDBOXX 320 DEFAULT_CUSTOMER_DEBT_LIMIT = ${IBAN_CURRENCY}:200 321 DEFAULT_ADMIN_DEBT_LIMIT = ${IBAN_CURRENCY}:2000 322 ALLOW_REGISTRATION = YES 323 PWD_HASH_CONFIG = { "cost": 4 } 324 PWD_AUTH_COMPAT = yes 325 326 [libeufin-bankdb-postgres] 327 CONFIG = postgres:///${IBAN_DB} 328 EOF 329 IBAN_ACTIVE='true' 330 dropdb $IBAN_DB >/dev/null 2>/dev/null || true 331 if ! createdb $IBAN_DB 2>> iban-setup.log 332 then 333 IBAN_ACTIVE='false' 334 else 335 libeufin-bank dbinit -c $CONF_IBAN >> iban-setup.log 2>&1 336 libeufin-bank serve -c $CONF_IBAN >> iban-setup.log 2>&1 & 337 IBAN_BANK_PID=$! 338 for n in `seq 1 50` 339 do 340 sleep 0.2 341 wget --tries=1 --timeout=1 "${IBAN_BANK_URL}config" \ 342 -o /dev/null -O /dev/null >/dev/null && break 343 done 344 make_bank_account "$CREDIT_USERNAME" "$CREDIT_PASSWORD" \ 345 "$PERSON_CREDIT_NAME" "$PAYTO_CREDIT" > /dev/null && 346 make_bank_account "$DEBIT_USERNAME" "$DEBIT_PASSWORD" \ 347 "Person Debit" "$PAYTO_DEBIT" > /dev/null && 348 libeufin-bank edit-account -c $CONF_IBAN \ 349 --debit_threshold="${IBAN_CURRENCY}:1000" \ 350 "$DEBIT_USERNAME" >> iban-setup.log 2>&1 || 351 IBAN_ACTIVE='false' 352 # Make sure the bank speaks the revenue API that 353 # anastasis-helper-authorization-iban expects (an empty history is 354 # answered with 204), so that a version mismatch disables IBAN 355 # authentication instead of failing challenges at run time. 356 CODE=`curl -s -o /dev/null -w "%{http_code}" \ 357 --user "${CREDIT_USERNAME}:${CREDIT_PASSWORD}" \ 358 "${IBAN_REVENUE_URL}history?limit=1"` 359 if test $IBAN_ACTIVE = 'true' && 360 test 200 != "$CODE" && test 204 != "$CODE" 361 then 362 REASON="revenue API at ${IBAN_REVENUE_URL} answered $CODE" 363 IBAN_ACTIVE='false' 364 kill $IBAN_BANK_PID 2> /dev/null || true 365 fi 366 fi 367 if test $IBAN_ACTIVE = 'false' 368 then 369 echo " DISABLED (${REASON:-see iban-setup.log})" 370 anastasis-config -c $CONF_4 -s authorization-iban -o ENABLED -V NO 371 else 372 anastasis-config -c $CONF_4 -s authorization-iban -o CURRENCY -V "${IBAN_CURRENCY}" 373 anastasis-config -c $CONF_4 -s authorization-iban -o CREDIT_IBAN -V "${IBAN_CREDIT}" 374 anastasis-config -c $CONF_4 -s authorization-iban -o BUSINESS_NAME -V "${PERSON_CREDIT_NAME}" 375 anastasis-config -c $CONF_4 -s authorization-iban -o WIRE_GATEWAY_URL \ 376 -V "${IBAN_REVENUE_URL}" 377 anastasis-config -c $CONF_4 -s authorization-iban -o WIRE_GATEWAY_AUTH_METHOD -V "basic" 378 anastasis-config -c $CONF_4 -s authorization-iban -o USERNAME -V "${CREDIT_USERNAME}" 379 anastasis-config -c $CONF_4 -s authorization-iban -o PASSWORD -V "${CREDIT_PASSWORD}" 380 anastasis-config -c $CONF_4 -s authorization-iban -o ENABLED -V YES 381 echo " OK" 382 fi 383 else 384 anastasis-config -c $CONF_4 -s authorization-iban -o ENABLED -V NO 385 fi 386 387 388 echo -n "Launching anastasis services ..." 389 # PREFIX="valgrind --log-file=anastasis-httpd.%p.log" 390 PREFIX="" 391 $PREFIX anastasis-httpd -L INFO -c $CONF_1 2> anastasis-httpd_1.log & 392 PPID_1=$! 393 $PREFIX anastasis-httpd -L INFO -c $CONF_2 2> anastasis-httpd_2.log & 394 PPID_2=$! 395 $PREFIX anastasis-httpd -L INFO -c $CONF_3 2> anastasis-httpd_3.log & 396 PPID_3=$! 397 $PREFIX anastasis-httpd -L INFO -c $CONF_4 2> anastasis-httpd_4.log & 398 PPID_4=$! 399 export PPID_1 400 export PPID_2 401 export PPID_3 402 export PPID_4 403 echo " OK" 404 405 echo -n "Waiting for anastasis services ..." 406 407 # Wait for anastasis services to be available 408 for n in `seq 1 50` 409 do 410 echo -n "." 411 sleep 0.1 412 OK=0 413 # anastasis_01 414 wget --tries=1 --timeout=1 http://localhost:8086/ -o /dev/null -O /dev/null >/dev/null || continue 415 # anastasis_02 416 wget --tries=1 --timeout=1 http://localhost:8087/ -o /dev/null -O /dev/null >/dev/null || continue 417 # anastasis_03 418 wget --tries=1 --timeout=1 http://localhost:8088/ -o /dev/null -O /dev/null >/dev/null || continue 419 # anastasis_04 420 wget --tries=1 --timeout=1 http://localhost:8089/ -o /dev/null -O /dev/null >/dev/null || continue 421 OK=1 422 break 423 done 424 425 if [ 1 != $OK ] 426 then 427 exit_skip "Failed to launch anastasis services" 428 fi 429 echo "OK" 430 431 export -f wire_transfer_to_anastasis 432 433 echo "You can now run anastasis-gtk in TESTLAND." 434 echo " " 435 echo "We will now start a sub-shell. Please note:" 436 echo '- to terminate the test environment by leaving the sub-shell use: exit' 437 if test $IBAN_ACTIVE = 'true' 438 then 439 echo '- for IBAN authentication use: wire_transfer_to_anastasis "$AMOUNT" "$SUBJECT"' 440 echo "- for your customer IBAN, use: ${IBAN_DEBIT}" 441 export IBAN_BANK_URL 442 export PAYTO_CREDIT 443 export DEBIT_USERNAME 444 export DEBIT_PASSWORD 445 export CONF_4 446 fi 447 if test $1 = 'fees' 448 then 449 echo '- to pay, use: taler-wallet-cli --wallet-db=$WALLET_DB handle-uri $PAY_URI -y' 450 export WALLET_DB 451 fi 452 453 echo '- use kill -SIGSTOP $PPID_$NUM ($NUM: 1-4) to suspend providers' 454 455 bash 456 457 exit 0