merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit 6d978efe14aa90564ce9257a23bcb2854ba07036
parent c22eb34d925c55e1a07710c6f0e8df5b954dece7
Author: Christian Grothoff <christian@grothoff.org>
Date:   Fri, 10 Apr 2020 23:21:11 +0200

implementing long-polling for refunds (#5985)

Diffstat:
Msrc/backend/taler-merchant-httpd.c | 77++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/backend/taler-merchant-httpd.h | 29++++++++++++++++++++++++++++-
Msrc/backend/taler-merchant-httpd_check-payment.c | 3++-
Msrc/backend/taler-merchant-httpd_pay.c | 65+++--------------------------------------------------------------
Msrc/backend/taler-merchant-httpd_poll-payment.c | 86++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/backend/taler-merchant-httpd_refund_increase.c | 5+++++
Msrc/include/taler_merchant_service.h | 4++++
Msrc/include/taler_merchant_testing_lib.h | 96++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/lib/merchant_api_poll_payment.c | 7+++++++
Msrc/lib/test_merchant_api.c | 2++
Msrc/lib/testing_api_cmd_poll_payment.c | 22++++++++++++++++++++++
11 files changed, 270 insertions(+), 126 deletions(-)

diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c @@ -300,15 +300,23 @@ do_resume (void *cls) * Suspend connection from @a sc until payment has been received. * * @param sc connection to suspend + * @param min_refund refund amount we are waiting on to be exceeded before resuming, + * NULL if we are not waiting for refunds */ void -TMH_long_poll_suspend (struct TMH_SuspendedConnection *sc) +TMH_long_poll_suspend (struct TMH_SuspendedConnection *sc, + const struct TALER_Amount *min_refund) { GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (payment_trigger_map, &sc->key, sc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); + if (NULL != min_refund) + { + sc->awaiting_refund = GNUNET_YES; + sc->refund_expected = *min_refund; + } sc->hn = GNUNET_CONTAINER_heap_insert (resume_timeout_heap, sc, sc->long_poll_timeout.abs_value_us); @@ -326,6 +334,73 @@ TMH_long_poll_suspend (struct TMH_SuspendedConnection *sc) /** + * Function called to resume suspended connections. + * + * @param cls pointer to a `struct TALER_Amount` indicating the refund amount, or NULL + * @param key key in the #payment_trigger_map + * @param value a `struct TMH_SuspendedConnection` to resume + * @return #GNUNET_OK (continue to iterate) + */ +static int +resume_operation (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + const struct TALER_Amount *have_refund = cls; + struct TMH_SuspendedConnection *sc = value; + + if ( (GNUNET_YES == sc->awaiting_refund) && + ( (NULL == have_refund) || + (1 != TALER_amount_cmp (have_refund, + &sc->refund_expected)) ) ) + return GNUNET_OK; /* skip */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Resuming operation suspended pending payment on key %s\n", + GNUNET_h2s (key)); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (payment_trigger_map, + key, + sc)); + GNUNET_assert (sc == + GNUNET_CONTAINER_heap_remove_node (sc->hn)); + sc->hn = NULL; + MHD_resume_connection (sc->con); + return GNUNET_OK; +} + + +/** + * Find out if we have any clients long-polling for @a order_id to be + * confirmed at merchant @a mpub, and if so, tell them to resume. + * + * @param order_id the order that was paid + * @param mpub the merchant's public key of the instance where the payment happened + * @param have_refund refunded amount, NULL if there was no refund + */ +void +TMH_long_poll_resume (const char *order_id, + const struct TALER_MerchantPublicKeyP *mpub, + const struct TALER_Amount *have_refund) +{ + struct GNUNET_HashCode key; + + TMH_compute_pay_key (order_id, + mpub, + &key); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Resuming operations suspended pending payment on key %s\n", + GNUNET_h2s (&key)); + GNUNET_CONTAINER_multihashmap_get_multiple (payment_trigger_map, + &key, + &resume_operation, + (void *) have_refund); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%u operations remain suspended pending payment\n", + GNUNET_CONTAINER_multihashmap_size (payment_trigger_map)); +} + + +/** * Create a taler://pay/ URI for the given @a con and @a order_id * and @a session_id and @a instance_id. * diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h @@ -289,6 +289,16 @@ struct TMH_SuspendedConnection */ struct GNUNET_TIME_Absolute long_poll_timeout; + /** + * Minimum refund amount to be exceeded (exclusive this value!) for resume. + */ + struct TALER_Amount refund_expected; + + /** + * #GNUNET_YES if we are waiting for a refund. + */ + int awaiting_refund; + }; @@ -412,9 +422,26 @@ TMH_compute_pay_key (const char *order_id, * Suspend connection from @a sc until payment has been received. * * @param sc connection to suspend + * @param min_refund refund amount we are waiting on to be exceeded before resuming, + * NULL if we are not waiting for refunds + */ +void +TMH_long_poll_suspend (struct TMH_SuspendedConnection *sc, + const struct TALER_Amount *min_refund); + + +/** + * Find out if we have any clients long-polling for @a order_id to be + * confirmed at merchant @a mpub, and if so, tell them to resume. + * + * @param order_id the order that was paid + * @param mpub the merchant's public key of the instance where the payment happened + * @param refund_amount refunded amount, if the trigger was a refund, otherwise NULL */ void -TMH_long_poll_suspend (struct TMH_SuspendedConnection *sc); +TMH_long_poll_resume (const char *order_id, + const struct TALER_MerchantPublicKeyP *mpub, + const struct TALER_Amount *refund_amount); /** diff --git a/src/backend/taler-merchant-httpd_check-payment.c b/src/backend/taler-merchant-httpd_check-payment.c @@ -194,7 +194,8 @@ send_pay_request (struct CheckPaymentRequestContext *cprc) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Suspending /check-payment on key %s\n", GNUNET_h2s (&cprc->sc.key)); - TMH_long_poll_suspend (&cprc->sc); + TMH_long_poll_suspend (&cprc->sc, + NULL); return MHD_YES; } diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c @@ -444,66 +444,6 @@ MH_force_pc_resume () /** - * Function called to resume suspended connections. - * - * @param cls NULL - * @param key key in the #payment_trigger_map - * @param value a `struct TMH_SuspendedConnection` to resume - * @return #GNUNET_OK (continue to iterate) - */ -static int -resume_operation (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct TMH_SuspendedConnection *sc = value; - - (void) cls; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Resuming operation suspended pending payment on key %s\n", - GNUNET_h2s (key)); - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (payment_trigger_map, - key, - sc)); - GNUNET_assert (sc == - GNUNET_CONTAINER_heap_remove_node (sc->hn)); - sc->hn = NULL; - MHD_resume_connection (sc->con); - return GNUNET_OK; -} - - -/** - * Find out if we have any clients long-polling for @a order_id to be - * confirmed at merchant @a mpub, and if so, tell them to resume. - * - * @param order_id the order that was paid - * @param mpub the merchant's public key of the instance where the payment happened - */ -static void -resume_suspended_payment_checks (const char *order_id, - const struct TALER_MerchantPublicKeyP *mpub) -{ - struct GNUNET_HashCode key; - - TMH_compute_pay_key (order_id, - mpub, - &key); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Resuming operations suspended pending payment on key %s\n", - GNUNET_h2s (&key)); - GNUNET_CONTAINER_multihashmap_get_multiple (payment_trigger_map, - &key, - &resume_operation, - NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%u operations remain suspended pending payment\n", - GNUNET_CONTAINER_multihashmap_size (payment_trigger_map)); -} - - -/** * Resume the given pay context and send the given response. * Stores the response in the @a pc and signals MHD to resume * the connection. Also ensures MHD runs immediately. @@ -2166,8 +2106,9 @@ begin_transaction (struct PayContext *pc) "Merchant database error: could not commit to mark proposal as 'paid'"); return; } - resume_suspended_payment_checks (pc->order_id, - &pc->mi->pubkey); + TMH_long_poll_resume (pc->order_id, + &pc->mi->pubkey, + NULL); generate_success_response (pc); return; } diff --git a/src/backend/taler-merchant-httpd_poll-payment.c b/src/backend/taler-merchant-httpd_poll-payment.c @@ -102,12 +102,24 @@ struct PollPaymentRequestContext struct TALER_Amount refund_amount; /** + * Minimum refund amount the client would like to poll for. + * Only initialized if + * @e awaiting_refund is set to #GNUNET_YES. + */ + struct TALER_Amount min_refund; + + /** * Set to #GNUNET_YES if this payment has been refunded and * @e refund_amount is initialized. */ int refunded; /** + * Set to #GNUNET_YES if this client is waiting for a refund. + */ + int awaiting_refund; + + /** * Initially #GNUNET_SYSERR. If we queued a response, set to the * result code (i.e. #MHD_YES or #MHD_NO). FIXME: fix type! */ @@ -124,8 +136,8 @@ struct PollPaymentRequestContext static void pprc_cleanup (struct TM_HandlerContext *hc) { - struct PollPaymentRequestContext *pprc = (struct - PollPaymentRequestContext *) hc; + struct PollPaymentRequestContext *pprc + = (struct PollPaymentRequestContext *) hc; if (NULL != pprc->contract_terms) json_decref (pprc->contract_terms); @@ -171,6 +183,27 @@ process_refunds_cb (void *cls, /** + * Suspend this @a pprc until the trigger is satisfied. + * + * @param ppr + */ +static void +suspend_pprc (struct PollPaymentRequestContext *pprc) +{ + TMH_compute_pay_key (pprc->order_id, + &pprc->mi->pubkey, + &pprc->sc.key); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Suspending /poll-payment on key %s\n", + GNUNET_h2s (&pprc->sc.key)); + TMH_long_poll_suspend (&pprc->sc, + (pprc->awaiting_refund) + ? &pprc->min_refund + : NULL); +} + + +/** * The client did not yet pay, send it the payment request. * * @param pprc check pay request context @@ -188,13 +221,7 @@ send_pay_request (struct PollPaymentRequestContext *pprc) if (0 != remaining.rel_value_us) { /* long polling: do not queue a response, suspend connection instead */ - TMH_compute_pay_key (pprc->order_id, - &pprc->mi->pubkey, - &pprc->sc.key); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Suspending /poll-payment on key %s\n", - GNUNET_h2s (&pprc->sc.key)); - TMH_long_poll_suspend (&pprc->sc); + suspend_pprc (pprc); return MHD_YES; } @@ -274,6 +301,7 @@ MH_handler_poll_payment (struct TMH_RequestHandler *rh, /* First time here, parse request and check order is known */ const char *long_poll_timeout_s; const char *cts; + const char *min_refund; pprc = GNUNET_new (struct PollPaymentRequestContext); pprc->hc.cc = &pprc_cleanup; @@ -343,6 +371,27 @@ MH_handler_poll_payment (struct TMH_RequestHandler *rh, { pprc->sc.long_poll_timeout = GNUNET_TIME_UNIT_ZERO_ABS; } + + min_refund = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "refund"); + if (NULL != min_refund) + { + if ( (GNUNET_OK != + TALER_string_to_amount (min_refund, + &pprc->min_refund)) || + (0 != strcasecmp (pprc->min_refund.currency, + TMH_currency) ) ) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_PARAMETER_MALFORMED, + "invalid amount given for refund argument"); + } + pprc->awaiting_refund = GNUNET_YES; + } + pprc->contract_url = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "contract_url"); @@ -495,6 +544,25 @@ MH_handler_poll_payment (struct TMH_RequestHandler *rh, TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR, "Merchant database error"); } + if ( (pprc->awaiting_refund) && + ( (! pprc->refunded) || + (1 != TALER_amount_cmp (&pprc->refund_amount, + &pprc->min_refund)) ) ) + { + /* Client is waiting for a refund larger than what we have, suspend + until timeout */ + struct GNUNET_TIME_Relative remaining; + + remaining = GNUNET_TIME_absolute_get_remaining (pprc->sc.long_poll_timeout); + if (0 != remaining.rel_value_us) + { + /* yes, indeed suspend */ + pprc->refunded = GNUNET_NO; + suspend_pprc (pprc); + return MHD_YES; + } + } + if (pprc->refunded) return TALER_MHD_reply_json_pack (connection, MHD_HTTP_OK, diff --git a/src/backend/taler-merchant-httpd_refund_increase.c b/src/backend/taler-merchant-httpd_refund_increase.c @@ -257,6 +257,11 @@ process_refund (struct MHD_Connection *connection, "Amount above payment"); } + /* Resume /public/poll-payments clients that may wait for this refund */ + TMH_long_poll_resume (order_id, + &mi->pubkey, + refund); + { MHD_RESULT ret; char *taler_refund_uri; diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h @@ -1386,6 +1386,9 @@ typedef void * before generating an unpaid response). Note that this is just provided to * the server, we as client will block until the response comes back or until * #TALER_MERCHANT_poll_payment_cancel() is called. + * @param min_refund long poll for the service to approve a refund exceeding this value; + * use NULL to not wait for any refund (only for payment). Only makes sense + * with a non-zero @a timeout. * @param poll_payment_cb callback which will work the response gotten from the backend * @param poll_payment_cb_cls closure to pass to @a poll_payment_cb * @return handle for this operation, NULL upon errors @@ -1398,6 +1401,7 @@ TALER_MERCHANT_poll_payment ( const struct GNUNET_HashCode *h_contract, const char *session_id, struct GNUNET_TIME_Relative timeout, + const struct TALER_Amount *min_refund, TALER_MERCHANT_PollPaymentCallback poll_payment_cb, void *poll_payment_cls); diff --git a/src/include/taler_merchant_testing_lib.h b/src/include/taler_merchant_testing_lib.h @@ -179,6 +179,7 @@ TALER_TESTING_cmd_check_payment_conclude (const char *label, * @param merchant_url merchant base url * @param proposal_reference the proposal whose payment status * is going to be checked. + * @param min_refund minimum refund to wait for * @param timeout which timeout to use * @return the command */ @@ -186,6 +187,7 @@ struct TALER_TESTING_Command TALER_TESTING_cmd_poll_payment_start (const char *label, const char *merchant_url, const char *proposal_reference, + const char *min_refund, struct GNUNET_TIME_Relative timeout); @@ -439,7 +441,6 @@ TALER_TESTING_cmd_merchant_track_transaction (const char *label, * @param check_bank_reference reference to a "check bank" CMD * that will provide the WTID and exchange URL to issue * the track against. - * @param pay_reference FIXME not used. */ struct TALER_TESTING_Command TALER_TESTING_cmd_merchant_track_transfer (const char *label, @@ -455,13 +456,12 @@ TALER_TESTING_cmd_merchant_track_transfer (const char *label, * @param index which signature to offer if there are multiple * on offer * @param merchant_sig set to the offered signature. - * * @return the trait */ struct TALER_TESTING_Trait -TALER_TESTING_make_trait_merchant_sig (unsigned int index, - const struct - TALER_MerchantSignatureP *merchant_sig); +TALER_TESTING_make_trait_merchant_sig ( + unsigned int index, + const struct TALER_MerchantSignatureP *merchant_sig); /** @@ -475,10 +475,10 @@ TALER_TESTING_make_trait_merchant_sig (unsigned int index, * @return #GNUNET_OK on success */ int -TALER_TESTING_get_trait_merchant_sig (const struct TALER_TESTING_Command *cmd, - unsigned int index, - struct TALER_MerchantSignatureP ** - merchant_sig); +TALER_TESTING_get_trait_merchant_sig ( + const struct TALER_TESTING_Command *cmd, + unsigned int index, + struct TALER_MerchantSignatureP **merchant_sig); /** * Obtain a reference to a proposal command. Any command that @@ -491,15 +491,14 @@ TALER_TESTING_get_trait_merchant_sig (const struct TALER_TESTING_Command *cmd, * @param cmd command to extract the trait from. * @param index which reference to pick if @a cmd has multiple * on offer. - * @param proposal_reference[out] set to the wanted reference. - * + * @param[out] proposal_reference set to the wanted reference. * @return #GNUNET_OK on success */ int -TALER_TESTING_get_trait_proposal_reference (const struct - TALER_TESTING_Command *cmd, - unsigned int index, - const char **proposal_reference); +TALER_TESTING_get_trait_proposal_reference ( + const struct TALER_TESTING_Command *cmd, + unsigned int index, + const char **proposal_reference); /** * Offer a proposal reference. @@ -534,7 +533,7 @@ TALER_TESTING_make_trait_coin_reference (unsigned int index, * @param cmd command to extract trait from * @param index which reference to pick if @a cmd has multiple * on offer - * @param coin_reference[out] set to the wanted reference. + * @param[out] coin_reference set to the wanted reference. * NOTE: a _single_ reference can contain * _multiple_ instances, using semi-colon as separator. * For example, a _single_ reference can be this: @@ -556,29 +555,25 @@ TALER_TESTING_get_trait_coin_reference (const struct TALER_TESTING_Command *cmd, * @param cmd command to extract trait from. * @param index index of the trait. * @param planchet_secrets[out] set to the wanted secrets. - * * @return #GNUNET_OK on success */ int -TALER_TESTING_get_trait_planchet_secrets (const struct - TALER_TESTING_Command *cmd, - unsigned int index, - struct TALER_PlanchetSecretsP ** - planchet_secrets); +TALER_TESTING_get_trait_planchet_secrets ( + const struct TALER_TESTING_Command *cmd, + unsigned int index, + struct TALER_PlanchetSecretsP **planchet_secrets); /** * Offer planchet secrets. * * @param index of the trait. * @param planchet_secrets set to the offered secrets. - * * @return the trait */ struct TALER_TESTING_Trait -TALER_TESTING_make_trait_planchet_secrets (unsigned int index, - const struct - TALER_PlanchetSecretsP * - planchet_secrets); +TALER_TESTING_make_trait_planchet_secrets ( + unsigned int index, + const struct TALER_PlanchetSecretsP *planchet_secrets); /** * Offer tip id. @@ -598,8 +593,7 @@ TALER_TESTING_make_trait_tip_id (unsigned int index, * @param cmd command to extract the trait from. * @param index which tip id to pick if @a * cmd has multiple on offer - * @param tip_id[out] set to the wanted data. - * + * @param[out] tip_id set to the wanted data. * @return #GNUNET_OK on success */ int @@ -618,9 +612,9 @@ TALER_TESTING_get_trait_tip_id (const struct TALER_TESTING_Command *cmd, * @return the trait */ struct TALER_TESTING_Trait -TALER_TESTING_make_trait_h_contract_terms (unsigned int index, - const struct - GNUNET_HashCode *h_contract_terms); +TALER_TESTING_make_trait_h_contract_terms ( + unsigned int index, + const struct GNUNET_HashCode *h_contract_terms); /** @@ -628,15 +622,14 @@ TALER_TESTING_make_trait_h_contract_terms (unsigned int index, * * @param cmd command to extract the trait from. * @param index index number of the trait to fetch. - * @param h_contract_terms[out] set to the wanted data. + * @param[out] h_contract_terms set to the wanted data. * @return #GNUNET_OK on success */ int -TALER_TESTING_get_trait_h_contract_terms (const struct - TALER_TESTING_Command *cmd, - unsigned int index, - const struct - GNUNET_HashCode **h_contract_terms); +TALER_TESTING_get_trait_h_contract_terms ( + const struct TALER_TESTING_Command *cmd, + unsigned int index, + const struct GNUNET_HashCode **h_contract_terms); /** * Offer refund entry. @@ -646,9 +639,9 @@ TALER_TESTING_get_trait_h_contract_terms (const struct * @return the trait */ struct TALER_TESTING_Trait -TALER_TESTING_make_trait_refund_entry (unsigned int index, - const struct - TALER_MERCHANT_RefundEntry *refund_entry); +TALER_TESTING_make_trait_refund_entry ( + unsigned int index, + const struct TALER_MERCHANT_RefundEntry *refund_entry); /** @@ -656,15 +649,14 @@ TALER_TESTING_make_trait_refund_entry (unsigned int index, * * @param cmd command to extract the trait from. * @param index the trait index. - * @param refund_entry[out] set to the wanted data. - * + * @param[out] refund_entry set to the wanted data. * @return #GNUNET_OK on success */ int -TALER_TESTING_get_trait_refund_entry (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct - TALER_MERCHANT_RefundEntry **refund_entry); +TALER_TESTING_get_trait_refund_entry ( + const struct TALER_TESTING_Command *cmd, + unsigned int index, + const struct TALER_MERCHANT_RefundEntry **refund_entry); /** * Create a /tip-authorize CMD, specifying the Taler error code @@ -699,12 +691,12 @@ TALER_TESTING_cmd_tip_authorize_with_ec (const char *label, * to test against such a case. * * @param label command label. - * * @return the command. */ struct TALER_TESTING_Command TALER_TESTING_cmd_tip_authorize_fake (const char *label); + /** * Create a /tip-authorize CMD. * @@ -810,10 +802,10 @@ TALER_TESTING_cmd_tip_pickup (const char *label, * * @param label command label * @param new_ip new instruction pointer's value. Note that, - * when the next instruction will be called, the interpreter - * will increment the ip _anyway_ so this value must be - * set to the index of the instruction we want to execute next - * MINUS one. + * when the next instruction will be called, the interpreter + * will increment the ip _anyway_ so this value must be + * set to the index of the instruction we want to execute next + * MINUS one. * @param counter counts how many times the rewinding has * to happen. */ diff --git a/src/lib/merchant_api_poll_payment.c b/src/lib/merchant_api_poll_payment.c @@ -205,6 +205,9 @@ handle_poll_payment_finished (void *cls, * before generating an unpaid response). Note that this is just provided to * the server, we as client will block until the response comes back or until * #TALER_MERCHANT_poll_payment_cancel() is called. + * @param min_refund long poll for the service to approve a refund exceeding this value; + * use NULL to not wait for any refund (only for payment). Only makes sense + * with a non-zero @a timeout. * @param poll_payment_cb callback which will work the response gotten from the backend * @param poll_payment_cb_cls closure to pass to @a poll_payment_cb * @return handle for this operation, NULL upon errors @@ -217,6 +220,7 @@ TALER_MERCHANT_poll_payment ( const struct GNUNET_HashCode *h_contract, const char *session_id, struct GNUNET_TIME_Relative timeout, + const struct TALER_Amount *min_refund, TALER_MERCHANT_PollPaymentCallback poll_payment_cb, void *poll_payment_cb_cls) { @@ -253,6 +257,9 @@ TALER_MERCHANT_poll_payment ( "h_contract", h_contract_s, (0 != ts) ? "timeout" : NULL, timeout_s, + (NULL != min_refund) ? "refund" : NULL, + (NULL != min_refund) ? TALER_amount2s ( + min_refund) : NULL, NULL); GNUNET_free (h_contract_s); GNUNET_free (timeout_s); diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c @@ -279,6 +279,7 @@ run (void *cls, TALER_TESTING_cmd_poll_payment_start ("poll-payment-1", merchant_url, "create-proposal-1", + NULL, GNUNET_TIME_UNIT_MILLISECONDS), TALER_TESTING_cmd_poll_payment_conclude ("poll-payment-conclude-1", MHD_HTTP_OK, @@ -287,6 +288,7 @@ run (void *cls, TALER_TESTING_cmd_poll_payment_start ("poll-payment-2", merchant_url, "create-proposal-1", + NULL, GNUNET_TIME_UNIT_MINUTES), TALER_TESTING_cmd_check_payment_start ("check-payment-2", merchant_url, diff --git a/src/lib/testing_api_cmd_poll_payment.c b/src/lib/testing_api_cmd_poll_payment.c @@ -85,6 +85,11 @@ struct PollPaymentStartState struct TALER_Amount refund; /** + * Refund to wait for, set if @e wait_for_refund is #GNUNET_YES + */ + struct TALER_Amount min_refund; + + /** * Final HTTP response status code. */ unsigned int http_status; @@ -99,6 +104,11 @@ struct PollPaymentStartState */ int refunded; + /** + * #GNUNET_YES if we are waiting for a refund. + */ + int wait_for_refund; + }; @@ -325,6 +335,9 @@ poll_payment_start_run (void *cls, h_contract, NULL, /* session id */ cps->timeout, + (GNUNET_YES == cps->wait_for_refund) + ? &cps->min_refund + : NULL, &poll_payment_cb, cps); GNUNET_assert (NULL != cps->cpo); @@ -341,6 +354,7 @@ poll_payment_start_run (void *cls, * @param merchant_url merchant base url * @param proposal_reference the proposal whose payment status * is going to be checked. + * @param min_refund minimum refund to wait for * @param timeout which timeout to use * @return the command */ @@ -348,6 +362,7 @@ struct TALER_TESTING_Command TALER_TESTING_cmd_poll_payment_start (const char *label, const char *merchant_url, const char *proposal_reference, + const char *min_refund, struct GNUNET_TIME_Relative timeout) { struct PollPaymentStartState *cps; @@ -356,6 +371,13 @@ TALER_TESTING_cmd_poll_payment_start (const char *label, cps->proposal_reference = proposal_reference; cps->merchant_url = merchant_url; cps->timeout = timeout; + if (NULL != min_refund) + { + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (min_refund, + &cps->min_refund)); + cps->wait_for_refund = GNUNET_YES; + } { struct TALER_TESTING_Command cmd = { .cls = cps,