/*
This file is part of TALER
Copyright (C) 2014-2019 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 3, or
(at your option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
*/
/**
* @file exchange/test_merchant_api.c
* @brief testcase to test exchange's HTTP API interface
* @author Sree Harsha Totakura
* @author Christian Grothoff
* @author Marcello Stanisci
*/
#include "platform.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "taler_merchant_testing_lib.h"
/**
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
#define CONFIG_FILE "test_merchant_api.conf"
/**
* Exchange base URL. Could also be taken from config.
*/
#define EXCHANGE_URL "http://localhost:8081/"
static const char *pickup_amounts_1[] = {"EUR:5", NULL};
/**
* URL of the fakebank.
*/
static char *fakebank_url;
/**
* Merchant base URL.
*/
static char *merchant_url;
/**
* Merchant process.
*/
static struct GNUNET_OS_Process *merchantd;
/**
* Exchange base URL.
*/
static char *exchange_url;
/**
* Auditor base URL; only used to fix FTBFS.
*/
static char *auditor_url;
/**
* Map for #intern()
*/
static struct GNUNET_CONTAINER_MultiHashMap *interned_strings;
/**
* Account number of the exchange at the bank.
*/
#define EXCHANGE_ACCOUNT_NO 2
/**
* Account number of some user.
*/
#define USER_ACCOUNT_NO 62
/**
* Account number used by the merchant
*/
#define MERCHANT_ACCOUNT_NO 3
/**
* User name. Never checked by fakebank.
*/
#define USER_LOGIN_NAME "user42"
/**
* User password. Never checked by fakebank.
*/
#define USER_LOGIN_PASS "pass42"
/**
* Execute the taler-exchange-wirewatch command with
* our configuration file.
*
* @param label label to use for the command.
*/
#define CMD_EXEC_WIREWATCH(label) \
TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE)
/**
* Execute the taler-exchange-aggregator command with
* our configuration file.
*
* @param label label to use for the command.
*/
#define CMD_EXEC_AGGREGATOR(label) \
TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE)
/**
* Run wire transfer of funds from some user's account to the
* exchange.
*
* @param label label to use for the command.
* @param amount amount to transfer, i.e. "EUR:1"
* @param url exchange_url
*/
#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
TALER_TESTING_cmd_fakebank_transfer (label, amount, \
fakebank_url, USER_ACCOUNT_NO, \
EXCHANGE_ACCOUNT_NO, \
USER_LOGIN_NAME, USER_LOGIN_PASS, \
EXCHANGE_URL)
/**
* Run wire transfer of funds from some user's account to the
* exchange.
*
* @param label label to use for the command.
* @param amount amount to transfer, i.e. "EUR:1"
*/
#define CMD_TRANSFER_TO_EXCHANGE_SUBJECT(label,amount,subject) \
TALER_TESTING_cmd_fakebank_transfer_with_subject \
(label, amount, fakebank_url, USER_ACCOUNT_NO, \
EXCHANGE_ACCOUNT_NO, USER_LOGIN_NAME, USER_LOGIN_PASS, \
subject)
static const char *
intern (const char *str)
{
struct GNUNET_HashCode hash;
const char *hs;
if (NULL == interned_strings)
interned_strings = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
GNUNET_assert (NULL != interned_strings);
GNUNET_CRYPTO_hash (str, strlen (str), &hash);
hs = GNUNET_CONTAINER_multihashmap_get (interned_strings, &hash);
if (NULL != hs)
return hs;
hs = GNUNET_strdup (str);
GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (
interned_strings,
&hash,
(void *) hs,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
return hs;
}
#define BUF_SZ 512
static const char *
merchant_url_internal (const char *instance_id)
{
char buf[BUF_SZ];
if (NULL == instance_id)
GNUNET_snprintf (buf,
BUF_SZ,
"%s",
merchant_url);
else
GNUNET_snprintf (buf,
BUF_SZ,
"%sinstances/%s/",
merchant_url,
instance_id);
return intern (buf);
}
static const char *
merchant_url_external (const char *instance_id)
{
char buf[BUF_SZ];
if (NULL == instance_id)
GNUNET_snprintf (buf,
BUF_SZ,
"%spublic/",
merchant_url);
else
GNUNET_snprintf (buf,
BUF_SZ,
"%spublic/instances/%s/",
merchant_url,
instance_id);
return intern (buf);
}
/**
* Main function that will tell the interpreter what commands to
* run.
*
* @param cls closure
*/
static void
run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct TALER_TESTING_Command pay[] = {
/**
* Move money to the exchange's bank account.
*/
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
"EUR:10.02"),
/**
* Make a reserve exist, according to the previous
* transfer.
*/
CMD_EXEC_WIREWATCH ("wirewatch-1"),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-2",
EXCHANGE_URL,
"EUR:10.02",
USER_ACCOUNT_NO,
EXCHANGE_ACCOUNT_NO),
TALER_TESTING_cmd_withdraw_amount
("withdraw-coin-1",
"create-reserve-1",
"EUR:5",
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount
("withdraw-coin-2",
"create-reserve-1",
"EUR:5",
MHD_HTTP_OK),
/**
* Check the reserve is depleted.
*/
TALER_TESTING_cmd_status ("withdraw-status-1",
"create-reserve-1",
"EUR:0",
MHD_HTTP_OK),
TALER_TESTING_cmd_proposal
("create-proposal-1",
merchant_url,
MHD_HTTP_OK,
"{\"max_fee\":\
{\"currency\":\"EUR\",\
\"value\":0,\
\"fraction\":50000000},\
\"order_id\":\"1\",\
\"refund_deadline\":\"\\/Date(0)\\/\",\
\"pay_deadline\":\"\\/Date(99999999999)\\/\",\
\"amount\":\
{\"currency\":\"EUR\",\
\"value\":5,\
\"fraction\":0},\
\"summary\": \"merchant-lib testcase\",\
\"fulfillment_url\": \"https://example.com/\",\
\"products\": [ {\"description\":\"ice cream\",\
\"value\":\"{EUR:5}\"} ] }"),
TALER_TESTING_cmd_check_payment ("check-payment-1",
merchant_url,
MHD_HTTP_OK,
"create-proposal-1",
GNUNET_NO),
TALER_TESTING_cmd_poll_payment_start ("poll-payment-1",
merchant_url,
"create-proposal-1",
GNUNET_TIME_UNIT_MILLISECONDS),
TALER_TESTING_cmd_poll_payment_conclude ("poll-payment-conclude-1",
MHD_HTTP_OK,
"poll-payment-1",
GNUNET_NO),
TALER_TESTING_cmd_poll_payment_start ("poll-payment-2",
merchant_url,
"create-proposal-1",
GNUNET_TIME_UNIT_MINUTES),
TALER_TESTING_cmd_check_payment_start ("check-payment-2",
merchant_url,
"create-proposal-1",
GNUNET_TIME_UNIT_MINUTES),
TALER_TESTING_cmd_pay ("deposit-simple",
merchant_url,
MHD_HTTP_OK,
"create-proposal-1",
"withdraw-coin-1",
"EUR:5",
"EUR:4.99",
"EUR:0.01"),
TALER_TESTING_cmd_poll_payment_conclude ("poll-payment-conclude-2",
MHD_HTTP_OK,
"poll-payment-2",
GNUNET_YES),
TALER_TESTING_cmd_check_payment_conclude ("check-payment-conclude-2",
MHD_HTTP_OK,
"check-payment-2",
GNUNET_YES),
TALER_TESTING_cmd_pay_abort ("pay-abort-2",
merchant_url,
"deposit-simple",
MHD_HTTP_FORBIDDEN),
TALER_TESTING_cmd_pay ("replay-simple",
merchant_url,
MHD_HTTP_OK,
"create-proposal-1",
"withdraw-coin-1",
"EUR:5",
"EUR:4.99",
"EUR:0.01"),
TALER_TESTING_cmd_check_bank_empty
("check_bank_empty-1"),
CMD_EXEC_AGGREGATOR ("run-aggregator"),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-498c",
EXCHANGE_URL,
"EUR:4.98",
EXCHANGE_ACCOUNT_NO,
MERCHANT_ACCOUNT_NO),
TALER_TESTING_cmd_check_bank_empty ("check_bank_empty-2"),
TALER_TESTING_cmd_end ()
};
struct TALER_TESTING_Command double_spending[] = {
TALER_TESTING_cmd_proposal
("create-proposal-2",
merchant_url,
MHD_HTTP_OK,
"{\"max_fee\":\
{\"currency\":\"EUR\",\
\"value\":0,\
\"fraction\":50000000},\
\"order_id\":\"2\",\
\"refund_deadline\":\"\\/Date(0)\\/\",\
\"pay_deadline\":\"\\/Date(99999999999)\\/\",\
\"amount\":\
{\"currency\":\"EUR\",\
\"value\":5,\
\"fraction\":0},\
\"summary\": \"useful product\",\
\"fulfillment_url\": \"https://example.com/\",\
\"products\": [ {\"description\":\"ice cream\",\
\"value\":\"{EUR:5}\"} ] }"),
TALER_TESTING_cmd_proposal_lookup ("fetch-proposal-2",
merchant_url,
MHD_HTTP_OK,
"create-proposal-2",
NULL),
TALER_TESTING_cmd_pay ("deposit-double-2",
merchant_url,
MHD_HTTP_CONFLICT,
"create-proposal-2",
"withdraw-coin-1",
"EUR:5",
"EUR:4.99",
"EUR:0.01"),
TALER_TESTING_cmd_history ("history-0",
merchant_url,
MHD_HTTP_OK,
/**
* all records to be returned; setting date as 0 lets the
* interpreter set it as 'now' + one hour delta, just to
* make sure it surpasses the proposal's timestamp.
*/GNUNET_TIME_UNIT_ZERO_ABS,
/**
* We only expect ONE result (create-proposal-1) to be
* included in /history response, because create-proposal-3
* did NOT go through because of double spending.
*/1, // nresult
10, // start
-10), // nrows
TALER_TESTING_cmd_end ()
};
struct TALER_TESTING_Command track[] = {
TALER_TESTING_cmd_merchant_track_transaction
("track-transaction-1",
merchant_url,
MHD_HTTP_OK,
"deposit-simple"),
TALER_TESTING_cmd_merchant_track_transfer
("track-transfer-1",
merchant_url,
MHD_HTTP_OK,
"check_bank_transfer-498c"),
TALER_TESTING_cmd_merchant_track_transfer
("track-transfer-again",
merchant_url,
MHD_HTTP_OK,
"check_bank_transfer-498c"),
TALER_TESTING_cmd_fakebank_transfer
("create-reserve-2",
"EUR:1",
fakebank_url,
USER_ACCOUNT_NO, EXCHANGE_ACCOUNT_NO,
"user62",
"pass62",
EXCHANGE_URL),
TALER_TESTING_cmd_fakebank_transfer_with_ref
("create-reserve-2b",
"EUR:4.01",
fakebank_url,
USER_ACCOUNT_NO, EXCHANGE_ACCOUNT_NO,
"user62",
"pass62",
"create-reserve-2",
EXCHANGE_URL),
CMD_EXEC_WIREWATCH ("wirewatch-2"),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-2a",
EXCHANGE_URL,
"EUR:1",
USER_ACCOUNT_NO,
EXCHANGE_ACCOUNT_NO),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-2b",
EXCHANGE_URL,
"EUR:4.01",
USER_ACCOUNT_NO,
EXCHANGE_ACCOUNT_NO),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
"create-reserve-2",
"EUR:5",
MHD_HTTP_OK),
TALER_TESTING_cmd_pay ("deposit-simple-2",
merchant_url,
MHD_HTTP_OK,
"create-proposal-2",
"withdraw-coin-2",
"EUR:5",
"EUR:4.99",
"EUR:0.01"),
CMD_EXEC_AGGREGATOR ("run-aggregator-2"),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-498c-2",
EXCHANGE_URL,
"EUR:4.98",
EXCHANGE_ACCOUNT_NO,
MERCHANT_ACCOUNT_NO),
TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"),
TALER_TESTING_cmd_merchant_track_transfer
("track-transfer-2",
merchant_url,
MHD_HTTP_OK,
"check_bank_transfer-498c-2"),
TALER_TESTING_cmd_merchant_track_transfer
("track-transfer-2-again",
merchant_url,
MHD_HTTP_OK,
"check_bank_transfer-498c-2"),
TALER_TESTING_cmd_merchant_track_transaction
("track-transaction-2",
merchant_url,
MHD_HTTP_OK,
"deposit-simple-2"),
TALER_TESTING_cmd_history ("history-1",
merchant_url,
MHD_HTTP_OK,
GNUNET_TIME_UNIT_ZERO_ABS,
/**
* Now we expect BOTH contracts (create-proposal-{1,2})
* to be included in /history response, because
* create-proposal-2 has now been correctly paid.
*/2,
10,
-10),
TALER_TESTING_cmd_end ()
};
struct TALER_TESTING_Command refund[] = {
TALER_TESTING_cmd_refund_increase
("refund-increase-1",
merchant_url,
"refund test",
"1", /* order ID */
"EUR:0.1",
"EUR:0.01",
MHD_HTTP_OK),
/* Ordinary refund. */
TALER_TESTING_cmd_refund_lookup ("refund-lookup-1",
merchant_url,
"refund-increase-1",
"deposit-simple",
"1",
MHD_HTTP_OK),
/* Trying to pick up refund from non existent proposal. */
TALER_TESTING_cmd_refund_lookup ("refund-lookup-non-existent",
merchant_url,
"refund-increase-1",
"deposit-simple",
"non-existend-id",
MHD_HTTP_NOT_FOUND),
/* Test /refund on a contract that was never paid. */
TALER_TESTING_cmd_proposal
("create-proposal-not-to-be-paid",
merchant_url,
MHD_HTTP_OK,
"{\"max_fee\":\
{\"currency\":\"EUR\",\
\"value\":0,\
\"fraction\":50000000},\
\"order_id\":\"1-unpaid\",\
\"refund_deadline\":\"\\/Date(0)\\/\",\
\"pay_deadline\":\"\\/Date(99999999999)\\/\",\
\"amount\":\
{\"currency\":\"EUR\",\
\"value\":5,\
\"fraction\":0},\
\"summary\": \"useful product\",\
\"fulfillment_url\": \"https://example.com/\",\
\"products\": [ {\"description\":\"ice cream\",\
\"value\":\"{EUR:5}\"} ] }"),
/* Try to increase a non paid proposal. */
TALER_TESTING_cmd_refund_increase
("refund-increase-unpaid-proposal",
merchant_url,
"refund test",
"1-unpaid",
"EUR:0.1",
"EUR:0.01",
MHD_HTTP_CONFLICT),
/* Try to increase a non existent proposal. */
TALER_TESTING_cmd_refund_increase
("refund-increase-unpaid-proposal",
merchant_url,
"refund test",
"non-existent-id",
"EUR:0.1",
"EUR:0.01",
MHD_HTTP_NOT_FOUND),
/**
* The following block will (1) create a new
* reserve, then (2) a proposal, then (3) pay for
* it, and finally (4) attempt to pick up a refund
* from it without any increasing taking place
* in the first place.
**/CMD_TRANSFER_TO_EXCHANGE ("create-reserve-unincreased-refund",
"EUR:5.01"),
CMD_EXEC_WIREWATCH ("wirewatch-unincreased-refund"),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-unincreased-refund",
EXCHANGE_URL,
"EUR:5.01",
USER_ACCOUNT_NO,
EXCHANGE_ACCOUNT_NO),
TALER_TESTING_cmd_withdraw_amount
("withdraw-coin-unincreased-refund",
"create-reserve-unincreased-refund",
"EUR:5",
MHD_HTTP_OK),
TALER_TESTING_cmd_proposal
("create-proposal-unincreased-refund",
merchant_url,
MHD_HTTP_OK,
"{\"max_fee\":\
{\"currency\":\"EUR\",\
\"value\":0,\
\"fraction\":50000000},\
\"order_id\":\"unincreased-proposal\",\
\"refund_deadline\":\"\\/Date(0)\\/\",\
\"pay_deadline\":\"\\/Date(99999999999)\\/\",\
\"amount\":\
{\"currency\":\"EUR\",\
\"value\":5,\
\"fraction\":0},\
\"summary\": \"merchant-lib testcase\",\
\"fulfillment_url\": \"https://example.com/\",\
\"products\": [ {\"description\":\"ice cream\",\
\"value\":\"{EUR:5}\"} ] }"),
TALER_TESTING_cmd_pay ("pay-unincreased-proposal",
merchant_url,
MHD_HTTP_OK,
"create-proposal-unincreased-refund",
"withdraw-coin-unincreased-refund",
"EUR:5",
"EUR:4.99",
"EUR:0.01"),
CMD_EXEC_AGGREGATOR ("run-aggregator-unincreased-refund"),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-unincreased-refund",
EXCHANGE_URL,
"EUR:4.98",
EXCHANGE_ACCOUNT_NO,
MERCHANT_ACCOUNT_NO),
/* Actually try to pick up the refund from the
* "unincreased proposal". */
TALER_TESTING_cmd_refund_lookup_with_amount
("refund-lookup-unincreased",
merchant_url,
NULL,
"pay-unincreased-proposal",
"unincreased-proposal",
MHD_HTTP_OK,
/* If a lookup is attempted on an unincreased proposal,
* the backend will simply respond with a empty refunded
* coin "set", but the HTTP response code is 200 OK. */
"EUR:0"),
TALER_TESTING_cmd_end ()
};
struct TALER_TESTING_Command tip[] = {
/* Test tipping. */
TALER_TESTING_cmd_fakebank_transfer_with_instance
("create-reserve-tip-1",
"EUR:20.04",
fakebank_url,
USER_ACCOUNT_NO,
EXCHANGE_ACCOUNT_NO,
USER_LOGIN_NAME,
USER_LOGIN_PASS,
"tip",
EXCHANGE_URL,
CONFIG_FILE),
CMD_EXEC_WIREWATCH ("wirewatch-3"),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-tip-1",
EXCHANGE_URL,
"EUR:20.04", USER_ACCOUNT_NO, EXCHANGE_ACCOUNT_NO),
TALER_TESTING_cmd_tip_authorize ("authorize-tip-1",
merchant_url_internal ("tip"),
exchange_url,
MHD_HTTP_OK,
"tip 1",
"EUR:5.01"),
TALER_TESTING_cmd_tip_authorize ("authorize-tip-2",
merchant_url_internal ("tip"),
exchange_url,
MHD_HTTP_OK,
"tip 2",
"EUR:5.01"),
/* This command tests the authorization of tip
* against a reserve that does not exist. This is
* implemented by passing a "tip instance" that
* specifies a reserve key that was never used to
* actually create a reserve. */TALER_TESTING_cmd_tip_authorize_with_ec
("authorize-tip-null",
merchant_url_internal ("nulltip"),
exchange_url,
MHD_HTTP_NOT_FOUND,
"tip 2",
"EUR:5.01",
TALER_EC_RESERVE_STATUS_UNKNOWN),
TALER_TESTING_cmd_tip_query ("query-tip-1",
merchant_url_internal ("tip"),
MHD_HTTP_OK),
TALER_TESTING_cmd_tip_query_with_amounts ("query-tip-2",
merchant_url_internal ("tip"),
MHD_HTTP_OK,
"EUR:0.0", // picked
"EUR:10.02", // auth
"EUR:20.04"),// ava
TALER_TESTING_cmd_tip_pickup ("pickup-tip-1",
merchant_url_external ("tip"),
MHD_HTTP_OK,
"authorize-tip-1",
pickup_amounts_1),
TALER_TESTING_cmd_tip_query_with_amounts ("query-tip-3",
merchant_url_internal ("tip"),
MHD_HTTP_OK,
"EUR:5.01", // picked
NULL, // auth
"EUR:15.03"),// ava
TALER_TESTING_cmd_tip_pickup ("pickup-tip-2",
merchant_url_external ("tip"),
MHD_HTTP_OK,
"authorize-tip-2",
pickup_amounts_1),
TALER_TESTING_cmd_tip_query_with_amounts ("query-tip-4",
merchant_url_internal ("tip"),
MHD_HTTP_OK,
"EUR:10.02", // pick
"EUR:10.02", // auth
"EUR:10.02"), // ava
TALER_TESTING_cmd_fakebank_transfer_with_instance
("create-reserve-insufficient-funds",
"EUR:1.01",
fakebank_url,
USER_ACCOUNT_NO,
EXCHANGE_ACCOUNT_NO,
USER_LOGIN_NAME,
USER_LOGIN_PASS,
"dtip",
EXCHANGE_URL,
CONFIG_FILE),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-insufficient-tip-funds",
EXCHANGE_URL,
"EUR:1.01",
USER_ACCOUNT_NO,
EXCHANGE_ACCOUNT_NO),
CMD_EXEC_WIREWATCH
("wirewatch-insufficient-tip-funds"),
TALER_TESTING_cmd_tip_authorize_with_ec
("authorize-tip-3-insufficient-funds",
merchant_url_internal ("dtip"),
exchange_url,
MHD_HTTP_PRECONDITION_FAILED,
"tip 3",
"EUR:2.02",
TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS),
TALER_TESTING_cmd_tip_authorize_with_ec
("authorize-tip-4-unknown-instance",
merchant_url_internal ("unknown"),
exchange_url,
MHD_HTTP_NOT_FOUND,
"tip 4",
"EUR:5.01",
TALER_EC_INSTANCE_UNKNOWN),
TALER_TESTING_cmd_tip_authorize_with_ec
("authorize-tip-5-notip-instance",
merchant_url,
exchange_url,
MHD_HTTP_NOT_FOUND,
"tip 5",
"EUR:5.01",
TALER_EC_TIP_AUTHORIZE_INSTANCE_DOES_NOT_TIP),
TALER_TESTING_cmd_tip_pickup_with_ec
("pickup-tip-3-too-much",
merchant_url_external ("tip"),
MHD_HTTP_CONFLICT,
"authorize-tip-1",
pickup_amounts_1,
TALER_EC_TIP_PICKUP_NO_FUNDS),
TALER_TESTING_cmd_tip_authorize_fake
("fake-tip-authorization"),
TALER_TESTING_cmd_tip_pickup_with_ec
("pickup-non-existent-id",
merchant_url_external ("tip"),
MHD_HTTP_NOT_FOUND,
"fake-tip-authorization",
pickup_amounts_1,
TALER_EC_TIP_PICKUP_TIP_ID_UNKNOWN),
TALER_TESTING_cmd_proposal
("create-proposal-tip-1",
merchant_url_internal ("tip"),
MHD_HTTP_OK,
"{\"max_fee\":\
{\"currency\":\"EUR\",\
\"value\":0,\
\"fraction\":50000000},\
\"order_id\":\"1-tip\",\
\"refund_deadline\":\"\\/Date(0)\\/\",\
\"pay_deadline\":\"\\/Date(99999999999)\\/\",\
\"amount\":\
{\"currency\":\"EUR\",\
\"value\":5,\
\"fraction\":0},\
\"summary\": \"useful product\",\
\"fulfillment_url\": \"https://example.com/\",\
\"products\": [ {\"description\":\"ice cream\",\
\"value\":\"{EUR:5}\"} ] }"),
TALER_TESTING_cmd_pay ("deposit-tip-simple",
merchant_url_external ("tip"),
MHD_HTTP_OK,
"create-proposal-tip-1",
"pickup-tip-1",
"EUR:5", // amount + fee
"EUR:4.99", // amount - fee
"EUR:0.01"), // refund fee
CMD_EXEC_AGGREGATOR ("aggregator-tip-1"),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-tip-498c",
EXCHANGE_URL,
"EUR:4.98",
EXCHANGE_ACCOUNT_NO,
MERCHANT_ACCOUNT_NO),
TALER_TESTING_cmd_check_bank_empty
("check_bank_empty-at-tips"),
TALER_TESTING_cmd_end ()
};
struct TALER_TESTING_Command pay_again[] = {
TALER_TESTING_cmd_fakebank_transfer
("create-reserve-10",
"EUR:10.02",
fakebank_url,
USER_ACCOUNT_NO,
EXCHANGE_ACCOUNT_NO,
USER_LOGIN_NAME,
USER_LOGIN_PASS,
EXCHANGE_URL),
CMD_EXEC_WIREWATCH ("wirewatch-10"),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-10",
EXCHANGE_URL,
"EUR:10.02", USER_ACCOUNT_NO, EXCHANGE_ACCOUNT_NO),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-10a",
"create-reserve-10",
"EUR:5",
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-10b",
"create-reserve-10",
"EUR:5",
MHD_HTTP_OK),
TALER_TESTING_cmd_status ("withdraw-status-10",
"create-reserve-10",
"EUR:0",
MHD_HTTP_OK),
TALER_TESTING_cmd_proposal
("create-proposal-10",
merchant_url,
MHD_HTTP_OK,
"{\"max_fee\":\
{\"currency\":\"EUR\",\
\"value\":0,\
\"fraction\":50000000},\
\"order_id\":\"10\",\
\"refund_deadline\":\"\\/Date(0)\\/\",\
\"pay_deadline\":\"\\/Date(99999999999)\\/\",\
\"amount\":\
{\"currency\":\"EUR\",\
\"value\":10,\
\"fraction\":0},\
\"summary\": \"merchant-lib testcase\",\
\"fulfillment_url\": \"https://example.com/\",\
\"products\": [ {\"description\":\"ice cream\",\
\"value\":\"{EUR:10}\"} ] }"),
TALER_TESTING_cmd_pay ("pay-fail-partial-double-10",
merchant_url,
MHD_HTTP_CONFLICT,
"create-proposal-10",
"withdraw-coin-10a;withdraw-coin-1",
"EUR:5",
"EUR:4.99",
"EUR:0.01"),
TALER_TESTING_cmd_pay_again
("pay-again-10",
merchant_url,
"pay-fail-partial-double-10",
"withdraw-coin-10a;withdraw-coin-10b",
"EUR:0.01",
MHD_HTTP_OK),
CMD_EXEC_AGGREGATOR ("run-aggregator-10"),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-9.97-10",
EXCHANGE_URL,
"EUR:9.97",
EXCHANGE_ACCOUNT_NO,
MERCHANT_ACCOUNT_NO),
TALER_TESTING_cmd_check_bank_empty ("check_bank_empty-10"),
TALER_TESTING_cmd_end ()
};
struct TALER_TESTING_Command pay_abort[] = {
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-11",
"EUR:10.02"),
CMD_EXEC_WIREWATCH ("wirewatch-11"),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-11",
EXCHANGE_URL,
"EUR:10.02",
USER_ACCOUNT_NO,
EXCHANGE_ACCOUNT_NO),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-11a",
"create-reserve-11",
"EUR:5",
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-11b",
"create-reserve-11",
"EUR:5",
MHD_HTTP_OK),
TALER_TESTING_cmd_status ("withdraw-status-11",
"create-reserve-11",
"EUR:0",
MHD_HTTP_OK),
TALER_TESTING_cmd_proposal
("create-proposal-11",
merchant_url,
MHD_HTTP_OK,
"{\"max_fee\":\
{\"currency\":\"EUR\",\
\"value\":0,\
\"fraction\":50000000},\
\"order_id\":\"11\",\
\"refund_deadline\":\"\\/Date(0)\\/\",\
\"pay_deadline\":\"\\/Date(99999999999)\\/\",\
\"amount\":\
{\"currency\":\"EUR\",\
\"value\":10,\
\"fraction\":0},\
\"summary\": \"merchant-lib testcase\",\
\"fulfillment_url\": \"https://example.com/\",\
\"products\": [ {\"description\":\"ice cream\",\
\"value\":\"{EUR:10}\"} ] }"),
TALER_TESTING_cmd_pay ("pay-fail-partial-double-11-good",
merchant_url,
MHD_HTTP_NOT_ACCEPTABLE,
"create-proposal-11",
"withdraw-coin-11a",
"EUR:5",
"EUR:4.99",
"EUR:0.01"),
TALER_TESTING_cmd_pay ("pay-fail-partial-double-11-bad",
merchant_url,
MHD_HTTP_CONFLICT,
"create-proposal-11",
"withdraw-coin-1",
"EUR:5",
"EUR:4.99",
"EUR:0.01"),
TALER_TESTING_cmd_pay_abort ("pay-abort-11",
merchant_url,
"pay-fail-partial-double-11-good",
MHD_HTTP_OK),
TALER_TESTING_cmd_pay_abort_refund ("pay-abort-refund-11",
/* abort reference */
"pay-abort-11",
0,
"EUR:5",
"EUR:0.01",
MHD_HTTP_OK),
CMD_EXEC_AGGREGATOR ("run-aggregator-11"),
TALER_TESTING_cmd_check_bank_empty ("check_bank_empty-11"),
TALER_TESTING_cmd_end ()
};
struct TALER_TESTING_Command commands[] = {
TALER_TESTING_cmd_batch ("pay",
pay),
TALER_TESTING_cmd_batch ("double-spending",
double_spending),
TALER_TESTING_cmd_batch ("track",
track),
TALER_TESTING_cmd_history
("history-2",
merchant_url,
MHD_HTTP_OK,
GNUNET_TIME_absolute_add (GNUNET_TIME_UNIT_ZERO_ABS,
GNUNET_TIME_UNIT_MICROSECONDS),
/* zero results expected, there isn't any row with id
* bigger than 10. */
0,
10,
10),
TALER_TESTING_cmd_batch ("refund",
refund),
TALER_TESTING_cmd_batch ("tip",
tip),
TALER_TESTING_cmd_batch ("pay-again",
pay_again),
TALER_TESTING_cmd_batch ("pay-abort",
pay_abort),
TALER_TESTING_cmd_history_default_start
("history-default-start",
merchant_url,
MHD_HTTP_OK,
GNUNET_TIME_UNIT_ZERO_ABS,
4, /* Expected number of records */
-100), /* Delta */
/**
* End the suite. Fixme: better to have a label for this
* too, as it shows a "(null)" token on logs.
*/
TALER_TESTING_cmd_end ()
};
TALER_TESTING_run_with_fakebank (is,
commands,
fakebank_url);
}
int
main (int argc,
char *const *argv)
{
unsigned int ret;
/* These environment variables get in the way... */
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
GNUNET_log_setup ("test-merchant-api",
"DEBUG",
NULL);
if (NULL ==
(fakebank_url = TALER_TESTING_prepare_fakebank
(CONFIG_FILE,
"account-exchange")))
return 77;
if (NULL ==
(merchant_url = TALER_TESTING_prepare_merchant (CONFIG_FILE)))
return 77;
TALER_TESTING_cleanup_files (CONFIG_FILE);
switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
&auditor_url,
&exchange_url))
{
case GNUNET_SYSERR:
GNUNET_break (0);
return 1;
case GNUNET_NO:
return 77;
case GNUNET_OK:
if (NULL == (merchantd =
TALER_TESTING_run_merchant (CONFIG_FILE,
merchant_url)))
return 1;
ret = TALER_TESTING_setup_with_exchange (&run,
NULL,
CONFIG_FILE);
GNUNET_OS_process_kill (merchantd, SIGTERM);
GNUNET_OS_process_wait (merchantd);
GNUNET_OS_process_destroy (merchantd);
GNUNET_free (merchant_url);
if (GNUNET_OK != ret)
return 1;
break;
default:
GNUNET_break (0);
return 1;
}
return 0;
}
/* end of test_merchant_api.c */