/*
  This file is part of TALER
  (C) 2018-2023 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
  <http://www.gnu.org/licenses/>
*/

/**
 * @file taler_merchant_testing_lib.h
 * @brief API for writing an interpreter to test Taler components
 * @author Christian Grothoff <christian@grothoff.org>
 * @author Marcello Shtanisci
 * @author Priscilla HUANG
 */
#ifndef TALER_MERCHANT_TESTING_LIB_H
#define TALER_MERCHANT_TESTING_LIB_H

#include <gnunet/gnunet_time_lib.h>
#include <taler/taler_testing_lib.h>
#include "taler_merchant_service.h"
#ifdef HAVE_DONAU_DONAU_SERVICE_H
#include "donau/donau_service.h"
#endif // HAVE_DONAU_DONAU_SERVICE_H

/* ********************* Helper functions ********************* */


#define MERCHANT_FAIL() \
  do {GNUNET_break (0); return NULL; } while (0)


/**
 * Extract hostname (and port) from merchant base URL.
 *
 * @param merchant_url full merchant URL (e.g. "http://host:8080/foo/bar/")
 * @return just the hostname and port ("hostname:8080")
 */
char *
TALER_MERCHANT_TESTING_extract_host (const char *merchant_url);


/* ************** Specific interpreter commands ************ */


/**
 * Define a "config" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        "config" request.
 * @param http_code expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_config (const char *label,
                          const char *merchant_url,
                          unsigned int http_code);


/**
 * Define a "GET /instances" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        GET /instances request.
 * @param http_status expected HTTP response code.
 * @param ... NULL-terminated list of labels (const char *) of
 *        product (commands) we expect to be returned in the list
 *        (assuming @a http_code is #MHD_HTTP_OK)
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_instances (const char *label,
                                          const char *merchant_url,
                                          unsigned int http_status,
                                          ...);


/**
 * Define a "POST /instances" CMD, simple version
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /instances request.
 * @param instance_id the ID of the instance to create
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_instances (const char *label,
                                           const char *merchant_url,
                                           const char *instance_id,
                                           unsigned int http_status);


/**
 * Define a "POST /private/auth" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /instances request.
 * @param instance_id the ID of the instance, or NULL
 * @param auth_token new auth token to use, can be NULL for no auth
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_instance_auth (const char *label,
                                               const char *merchant_url,
                                               const char *instance_id,
                                               const char *auth_token,
                                               unsigned int http_status);


/**
 * Define a "POST /private/token" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /instances request.
 * @param instance_id the ID of the instance, or NULL
 * @param scope scope to request, can be NULL
 * @param duration requested token validity duration
 * @param refreshable should token be refreshable
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_instance_token (const char *label,
                                                const char *merchant_url,
                                                const char *instance_id,
                                                const char *scope,
                                                struct GNUNET_TIME_Relative
                                                duration,
                                                bool refreshable,
                                                unsigned int http_status);

/**
 * Set the access token gotten through another CMD
 *
 * @param label command label.
 * @param cmd_job_label the other command exposing the bearer_token trait.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_set_instance_token (const char *label,
                                               const char *cmd_job_label);

/**
 * Define a "DELETE /private/token" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /instances request.
 * @param instance_id the ID of the instance, or NULL
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_instance_token (const char *label,
                                                  const char *merchant_url,
                                                  const char *instance_id,
                                                  unsigned int http_status);

/**
 * Define a "POST /instances" CMD.  Comprehensive version.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /instances request.
 * @param instance_id the ID of the instance to query
 * @param name name of the merchant instance
 * @param address physical address of the merchant instance
 * @param jurisdiction jurisdiction of the merchant instance
 * @param use_stefan enable STEFAN curve
 * @param default_wire_transfer_delay default wire transfer delay merchant will ask for
 * @param default_pay_delay default validity period for offers merchant makes
 * @param auth_token authorization token needed to access the instance, can be NULL
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_instances2 (
  const char *label,
  const char *merchant_url,
  const char *instance_id,
  const char *name,
  json_t *address,
  json_t *jurisdiction,
  bool use_stefan,
  struct GNUNET_TIME_Relative default_wire_transfer_delay,
  struct GNUNET_TIME_Relative default_pay_delay,
  const char *auth_token,
  unsigned int http_status);


/**
 * Define a "POST /account" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /instances request.
 * @param payto_uri URIs of the bank account to add to the merchant instance
 * @param credit_facade_url credit facade URL to configure, can be NULL
 * @param credit_facade_credentials credit facade credentials to use, can be NULL
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_account (
  const char *label,
  const char *merchant_url,
  struct TALER_FullPayto payto_uri,
  const char *credit_facade_url,
  const json_t *credit_facade_credentials,
  unsigned int http_status);


/**
 * Define a "PATCH /account" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /instances request.
 * @param create_account_ref reference to account setup command
 * @param credit_facade_url credit facade URL to configure, can be NULL
 * @param credit_facade_credentials credit facade credentials to use, can be NULL
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_patch_account (
  const char *label,
  const char *merchant_url,
  const char *create_account_ref,
  const char *credit_facade_url,
  const json_t *credit_facade_credentials,
  unsigned int http_status);


/**
 * Define a "DELETE /account" CMD.
 *
 * @param label command label.
 * @param create_account_ref reference to account setup command
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_account (
  const char *label,
  const char *create_account_ref,
  unsigned int http_status);


/**
 * Define a "PATCH /instances/$ID" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        PATCH /instance request.
 * @param instance_id the ID of the instance to query
 * @param name name of the merchant instance
 * @param address physical address of the merchant instance
 * @param jurisdiction jurisdiction of the merchant instance
 * @param use_stefan use STEFAN curve
 * @param default_wire_transfer_delay default wire transfer delay merchant will ask for
 * @param default_pay_delay default validity period for offers merchant makes
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_patch_instance (
  const char *label,
  const char *merchant_url,
  const char *instance_id,
  const char *name,
  json_t *address,
  json_t *jurisdiction,
  bool use_stefan,
  struct GNUNET_TIME_Relative default_wire_transfer_delay,
  struct GNUNET_TIME_Relative default_pay_delay,
  unsigned int http_status);


/**
 * Define a "GET instance" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        GET /instances/$ID request.
 * @param instance_id the ID of the instance to query
 * @param http_status expected HTTP response code.
 * @param instance_reference reference to a "POST /instances" or "PATCH /instances/$ID" CMD
 *        that will provide what we expect the backend to return to us
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_instance (const char *label,
                                         const char *merchant_url,
                                         const char *instance_id,
                                         unsigned int http_status,
                                         const char *instance_reference);


/**
 * Define a "PURGE instance" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        PURGE /instances/$ID request.
 * @param instance_id the ID of the instance to query
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_purge_instance (const char *label,
                                           const char *merchant_url,
                                           const char *instance_id,
                                           unsigned int http_status);


/**
 * Define a "DELETE instance" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        DELETE /instances/$ID request.
 * @param instance_id the ID of the instance to query
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_instance (const char *label,
                                            const char *merchant_url,
                                            const char *instance_id,
                                            unsigned int http_status);


/* ******************* /products **************** */


/**
 * Define a "POST /products" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /products request.
 * @param product_id the ID of the product to query
 * @param description description of the product
 * @param description_i18n Map from IETF BCP 47 language tags to localized descriptions
 * @param unit unit in which the product is measured (liters, kilograms, packages, etc.)
 * @param price the price for one @a unit of the product, zero is used to imply that
 *              this product is not sold separately or that the price is not fixed and
 *              must be supplied by the front-end.  If non-zero, price must include
 *              applicable taxes.
 * @param image base64-encoded product image
 * @param taxes list of taxes paid by the merchant
 * @param total_stock in @a units, -1 to indicate "infinite" (i.e. electronic books)
 * @param minimum_age minimum age required for buying this product
 * @param address where the product is in stock
 * @param next_restock when the next restocking is expected to happen, 0 for unknown,
 *                     #GNUNET_TIME_UNIT_FOREVER_TS for 'never'.
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_products2 (
  const char *label,
  const char *merchant_url,
  const char *product_id,
  const char *description,
  json_t *description_i18n,
  const char *unit,
  const char *price,
  const char *image,
  json_t *taxes,
  int64_t total_stock,
  uint32_t minimum_age,
  json_t *address,
  struct GNUNET_TIME_Timestamp next_restock,
  unsigned int http_status);


struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_products3 (
  const char *label,
  const char *merchant_url,
  const char *product_id,
  const char *description,
  json_t *description_i18n,
  const char *unit,
  const char *price,
  const char *image,
  json_t *taxes,
  int64_t total_stock,
  uint32_t total_stock_frac,
  bool unit_allow_fraction,
  uint32_t minimum_age,
  json_t *address,
  struct GNUNET_TIME_Timestamp next_restock,
  unsigned int http_status);


/**
 * Define a "POST /products" CMD, simple version
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /products request.
 * @param product_id the ID of the product to create
 * @param description name of the product
 * @param price price of the product
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_products (const char *label,
                                          const char *merchant_url,
                                          const char *product_id,
                                          const char *description,
                                          const char *price,
                                          unsigned int http_status);


/**
 * Define a "PATCH /products/$ID" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        PATCH /product request.
 * @param product_id the ID of the product to query
 * @param description description of the product
 * @param description_i18n Map from IETF BCP 47 language tags to localized descriptions
 * @param unit unit in which the product is measured (liters, kilograms, packages, etc.)
 * @param price the price for one @a unit of the product, zero is used to imply that
 *              this product is not sold separately or that the price is not fixed and
 *              must be supplied by the front-end.  If non-zero, price must include
 *              applicable taxes.
 * @param image base64-encoded product image
 * @param taxes list of taxes paid by the merchant
 * @param total_stock in @a units, -1 to indicate "infinite" (i.e. electronic books)
 * @param total_lost in @a units, must be larger than previous values, and may
 *               not exceed total_stock minus total_sold; if it does, the transaction
 *               will fail with a #MHD_HTTP_CONFLICT HTTP status code
 * @param address where the product is in stock
 * @param next_restock when the next restocking is expected to happen, 0 for unknown,
 *                     #GNUNET_TIME_UNIT_FOREVER_ABS for 'never'.
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_patch_product (
  const char *label,
  const char *merchant_url,
  const char *product_id,
  const char *description,
  json_t *description_i18n,
  const char *unit,
  const char *price,
  const char *image,
  json_t *taxes,
  int64_t total_stock,
  uint64_t total_lost,
  json_t *address,
  struct GNUNET_TIME_Timestamp next_restock,
  unsigned int http_status);


struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_patch_product2 (
  const char *label,
  const char *merchant_url,
  const char *product_id,
  const char *description,
  json_t *description_i18n,
  const char *unit,
  const char *price,
  const char *image,
  json_t *taxes,
  int64_t total_stock,
  uint32_t total_stock_frac,
  bool unit_allow_fraction,
  uint64_t total_lost,
  json_t *address,
  struct GNUNET_TIME_Timestamp next_restock,
  unsigned int http_status);


/**
 * Define a "GET /products" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        GET /products request.
 * @param http_status expected HTTP response code.
 * @param ... NULL-terminated list of labels (const char *) of
 *        product (commands) we expect to be returned in the list
 *        (assuming @a http_code is #MHD_HTTP_OK)
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_products (const char *label,
                                         const char *merchant_url,
                                         unsigned int http_status,
                                         ...);

/**
 * Expectations for fractional unit fields when checking a product.
 */
struct TALER_TESTING_ProductUnitExpectations
{
  /**
   * Whether @e unit_allow_fraction is provided.
   */
  bool have_unit_allow_fraction;

  /**
   * Expected fractional flag.
   */
  bool unit_allow_fraction;

  /**
   * Whether @e unit_precision_level is provided.
   */
  bool have_unit_precision_level;

  /**
   * Expected fractional precision.
   */
  uint32_t unit_precision_level;
};


/**
 * Define a "GET product" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        GET /products/$ID request.
 * @param product_id the ID of the product to query
 * @param http_status expected HTTP response code.
 * @param product_reference reference to a "POST /products" or "PATCH /products/$ID" CMD
 *        that will provide what we expect the backend to return to us
 * @param unit_expectations optional explicit expectations for the fractional fields
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_product2 (
  const char *label,
  const char *merchant_url,
  const char *product_id,
  unsigned int http_status,
  const char *product_reference,
  const struct TALER_TESTING_ProductUnitExpectations *unit_expectations);


/**
 * Legacy helper kept for compatibility.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_product (const char *label,
                                        const char *merchant_url,
                                        const char *product_id,
                                        unsigned int http_status,
                                        const char *product_reference);

struct TALER_TESTING_Command
TALER_TESTING_cmd_get_product_image (const char *label,
                                     const char *merchant_url,
                                     const char *product_reference,
                                     const char *image_hash,
                                     unsigned int http_status);


/**
 * Define a "LOCK /products/$ID" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        LOCK /product request.
 * @param product_id the ID of the product to lock.
 * @param duration how long the lock should last.
 * @param quantity how money units to lock.
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_lock_product (
  const char *label,
  const char *merchant_url,
  const char *product_id,
  struct GNUNET_TIME_Relative duration,
  uint32_t quantity,
  unsigned int http_status);


struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_lock_product2 (
  const char *label,
  const char *merchant_url,
  const char *product_id,
  struct GNUNET_TIME_Relative duration,
  uint32_t quantity,
  uint32_t quantity_frac,
  bool use_fractional_quantity,
  unsigned int http_status);


/**
 * Define a "DELETE product" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        DELETE /products/$ID request.
 * @param product_id the ID of the product to query
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_product (const char *label,
                                           const char *merchant_url,
                                           const char *product_id,
                                           unsigned int http_status);


/* ******************* /orders **************** */

/**
 * Make the "proposal" command.
 *
 * @param label command label
 * @param cfg configuration to use
 * @param merchant_url base URL of the merchant serving
 *        the proposal request.
 * @param http_status expected HTTP status.
 * @param order_id the name of the order to add.
 * @param refund_deadline the deadline for refunds on this order.
 * @param pay_deadline the deadline for payment on this order.
 * @param amount the amount this order is for.
 * @return the command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_orders (
  const char *label,
  const struct GNUNET_CONFIGURATION_Handle *cfg,
  const char *merchant_url,
  unsigned int http_status,
  const char *order_id,
  struct GNUNET_TIME_Timestamp refund_deadline,
  struct GNUNET_TIME_Timestamp pay_deadline,
  const char *amount);


/**
 * Make the "proposal" command AVOIDING claiming the order.
 *
 * @param label command label
 * @param merchant_url base URL of the merchant serving
 *        the proposal request.
 * @param http_status expected HTTP status.
 * @param order_id the name of the order to add.
 * @param refund_deadline the deadline for refunds on this order.
 * @param pay_deadline the deadline for payment on this order.
 * @param amount the amount this order is for.
 * @return the command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_orders_no_claim (
  const char *label,
  const char *merchant_url,
  unsigned int http_status,
  const char *order_id,
  struct GNUNET_TIME_Timestamp refund_deadline,
  struct GNUNET_TIME_Timestamp pay_deadline,
  const char *amount);


/**
 * Make the "proposal" command.
 *
 * @param label command label
 * @param cfg configuration to use
 * @param merchant_url base URL of the merchant serving
 *        the proposal request.
 * @param http_status expected HTTP status.
 * @param order_id the name of the order to add.
 * @param refund_deadline the deadline for refunds on this order.
 * @param pay_deadline the deadline for payment on this order.
 * @param claim_token whether to generate a claim token.
 * @param amount the amount this order is for.
 * @param payment_target payment target for the order.
 * @param products a string indicating the products this order will be
 *        purchasing. Should be formatted as
 *        "[product_id]/[quantity];...".
 * @param locks a string of references to lock product commands that should
 *        be formatted as "[lock_1];[lock_2];...".
 * @param duplicate_of if not NULL, a reference to a previous order command
 *        that should be duplicated and checked for an identical response.
 * @return the command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_orders2 (
  const char *label,
  const struct GNUNET_CONFIGURATION_Handle *cfg,
  const char *merchant_url,
  unsigned int http_status,
  const char *order_id,
  struct GNUNET_TIME_Timestamp refund_deadline,
  struct GNUNET_TIME_Timestamp pay_deadline,
  bool claim_token,
  const char *amount,
  const char *payment_target,
  const char *products,
  const char *locks,
  const char *duplicate_of);


/**
 * Create an order with a specific fulfillment URL.
 * Does not claim the order.
 *
 * @param label command label
 * @param cfg configuration to use
 * @param merchant_url base URL of the merchant serving
 *        the proposal request
 * @param http_status expected HTTP status
 * @param order_id ID of the order to create
 * @param refund_deadline the deadline for refunds on this order
 * @param pay_deadline the deadline for payment on this order
 * @param fulfillment_url the fulfillment URL to use
 * @param amount the amount this order is for
 * @return the command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_orders3 (
  const char *label,
  const struct GNUNET_CONFIGURATION_Handle *cfg,
  const char *merchant_url,
  unsigned int http_status,
  const char *order_id,
  struct GNUNET_TIME_Timestamp refund_deadline,
  struct GNUNET_TIME_Timestamp pay_deadline,
  const char *fulfillment_url,
  const char *amount);


/**
 * Create an order with a choices array with input and output tokens.
 *
 * @param label command label
 * @param cfg configuration to use
 * @param merchant_url base URL of the merchant serving
 *        the proposal request.
 * @param http_status expected HTTP status.
 * @param token_family_slug slug of the token family to use
 * @param choice_description description of the choice
 * @param choice_description_i18n json of description translations
 * @param num_inputs number of input tokens.
 * @param num_outputs number of output tokens.
 * @param order_id the name of the order to add.
 * @param refund_deadline the deadline for refunds on this order.
 * @param pay_deadline the deadline for payment on this order.
 * @param amount the amount this order is for.
 * @return the command
 */

struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_orders_choices (
  const char *label,
  const struct GNUNET_CONFIGURATION_Handle *cfg,
  const char *merchant_url,
  unsigned int http_status,
  const char *token_family_slug,
  const char *choice_description,
  json_t *choice_description_i18n,
  unsigned int num_inputs,
  unsigned int num_outputs,
  const char *order_id,
  struct GNUNET_TIME_Timestamp refund_deadline,
  struct GNUNET_TIME_Timestamp pay_deadline,
  const char *amount);


/**
 * Create an order with a choices array with output choice for donau.
 *
 * @param label command label
 * @param cfg configuration to use
 * @param merchant_url base URL of the merchant serving
 *        the proposal request.
 * @param http_status expected HTTP status.
 * @param order_id the name of the order to add.
 * @param refund_deadline the deadline for refunds on this order.
 * @param pay_deadline the deadline for payment on this order.
 * @param amount the amount this order is for.
 * @return the command
 */

struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_orders_donau (
  const char *label,
  const struct GNUNET_CONFIGURATION_Handle *cfg,
  const char *merchant_url,
  unsigned int http_status,
  const char *order_id,
  struct GNUNET_TIME_Timestamp refund_deadline,
  struct GNUNET_TIME_Timestamp pay_deadline,
  const char *amount);

/**
 * Define a "GET /orders" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        GET /orders request.
 * @param http_status expected HTTP response code.
 * @param ... NULL-terminated list of labels (const char *) of
 *        order (commands) we expect to be returned in the list
 *        (assuming @a http_code is #MHD_HTTP_OK)
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_orders (const char *label,
                                       const char *merchant_url,
                                       unsigned int http_status,
                                       ...);


/**
 * Start a long poll for GET /private/orders.
 *
 * FIXME: needs additional arguments to specify range to long poll for!
 *
 * @param label the command label
 * @param merchant_url base URL of the merchant which will
 *        serve the request.
 * @param timeout how long to wait for the request to complete
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_poll_orders_start (const char *label,
                                     const char *merchant_url,
                                     struct GNUNET_TIME_Relative timeout);


/**
 * Complete a long poll for GET /private/orders.
 *
 * @param label the command label
 * @param http_status expected HTTP response code
 * @param poll_start_reference reference to the #TALER_TESTING_cmd_poll_orders_start command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_poll_orders_conclude (
  const char *label,
  unsigned int http_status,
  const char *poll_start_reference);


/**
 * Define a GET /orders/$ORDER_ID CMD.
 *
 * @param label the command label
 * @param merchant_url base URL of the merchant which will
 *        serve the request.
 * @param order_reference reference to a command that created an order.
 * @param paid whether the order has been paid for or not.
 * @param refunded whether the order has been refunded.
 * @param refund_pending whether the order has refunds that haven't been obtained.
 * @param http_status expected HTTP response code for the request.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_wallet_get_order (
  const char *label,
  const char *merchant_url,
  const char *order_reference,
  bool paid,
  bool refunded,
  bool refund_pending,
  unsigned int http_status);


/**
 * Define a GET /orders/$ORDER_ID CMD.
 *
 * @param label the command label
 * @param merchant_url base URL of the merchant which will
 *        serve the request.
 * @param order_reference reference to a command that created an order.
 * @param session_id session ID to check for
 * @param paid whether the order has been paid for or not.
 * @param refunded whether the order has been refunded.
 * @param refund_pending whether the order has refunds that haven't been obtained.
 * @param repurchase_order_ref command of a paid equivalent order the merchant should be referring us to, or NULL
 * @param http_status expected HTTP response code for the request.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_wallet_get_order2 (
  const char *label,
  const char *merchant_url,
  const char *order_reference,
  const char *session_id,
  bool paid,
  bool refunded,
  bool refund_pending,
  const char *repurchase_order_ref,
  unsigned int http_status);


/**
 * Start a long poll for GET /orders/$ORDER_ID.
 *
 * @param label the command label
 * @param merchant_url base URL of the merchant which will
 *        serve the request.
 * @param order_ref reference to a command that created an order.
 * @param timeout how long to wait for the request to complete
 * @param await_refund NULL to not wait for refund, amount of value
 *         zero to wait for any refund amount, non-zero to poll
 *         for refund exceeding the given amount
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_wallet_poll_order_start (
  const char *label,
  const char *merchant_url,
  const char *order_ref,
  struct GNUNET_TIME_Relative timeout,
  const char *await_refund);


/**
 * Start a long poll for GET /orders/$ORDER_ID.
 *
 * @param label the command label
 * @param merchant_url base URL of the merchant which will
 *        serve the request.
 * @param order_ref reference to a command that created an order.
 * @param timeout how long to wait for the request to complete
 * @param await_refund NULL to not wait for refund, amount of value
 *         zero to wait for any refund amount, non-zero to poll
 *         for refund exceeding the given amount
 * @param session_id which session ID to use
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_wallet_poll_order_start2 (
  const char *label,
  const char *merchant_url,
  const char *order_ref,
  struct GNUNET_TIME_Relative timeout,
  const char *await_refund,
  const char *session_id);


/**
 * Complete a long poll for GET /orders/$ORDER_ID.
 *
 * @param label the command label
 * @param expected_http_status expected HTTP response code
 * @param expected_refund_amount refund expected, NULL for no refund expected
 * @param poll_start_reference reference to the #TALER_TESTING_cmd_wallet_poll_order_start command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_wallet_poll_order_conclude (
  const char *label,
  unsigned int expected_http_status,
  const char *expected_refund_amount,
  const char *poll_start_reference);


/**
 * Complete a long poll for GET /orders/$ORDER_ID.
 *
 * @param label the command label
 * @param expected_http_status expected HTTP response code
 * @param expected_refund_amount refund expected, NULL for no refund expected
 * @param poll_start_reference reference to the #TALER_TESTING_cmd_wallet_poll_order_start command
 * @param already_paid_order_id ID of an already paid order we expect to get returned
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_wallet_poll_order_conclude2 (
  const char *label,
  unsigned int expected_http_status,
  const char *expected_refund_amount,
  const char *poll_start_reference,
  const char *already_paid_order_id);


/**
 * Define a GET /private/orders/$ORDER_ID CMD.
 *
 * @param label the command label
 * @param merchant_url base URL of the merchant which will
 *        serve the request.
 * @param order_reference reference to a command that created an order.
 * @param osc expected order status
 * @param refunded whether the order has been refunded.
 * @param http_status expected HTTP response code for the request.
 * @param ... NULL-terminated list of labels (const char *) of
 *        refunds (commands) we expect to be aggregated in the transfer
 *        (assuming @a http_code is #MHD_HTTP_OK). If @e refunded is false,
 *        this parameter is ignored.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_order (
  const char *label,
  const char *merchant_url,
  const char *order_reference,
  enum TALER_MERCHANT_OrderStatusCode osc,
  bool refunded,
  unsigned int http_status,
  ...);


/**
 * Define a GET /private/orders/$ORDER_ID CMD.
 *
 * @param label the command label
 * @param merchant_url base URL of the merchant which will
 *        serve the request.
 * @param order_reference reference to a command that created an order.
 * @param osc expected order status
 * @param wired whether the order has been wired or not.
 * @param transfers NULL-terminated list of labels (const char *) of
 *        wire transfers (commands) we expect to be aggregated in the order
 *        (assuming @a http_code is #MHD_HTTP_OK). If @e paid is false, this
 *        parameter is ignored.
 * @param refunded whether the order has been refunded.
 * @param refunds NULL-terminated list of labels (const char *) of
 *        refunds (commands) we expect to be aggregated in the order
 *        (assuming @a http_code is #MHD_HTTP_OK). If @e refunded is false,
 *        this parameter is ignored.
 * @param forgets a NULL-terminated list of references to forget commands
 *        that apply to the order we are querying. If NULL, this is
 *        interpreted as no forgets are expected.
 * @param http_status expected HTTP response code for the request.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_order2 (
  const char *label,
  const char *merchant_url,
  const char *order_reference,
  enum TALER_MERCHANT_OrderStatusCode osc,
  bool wired,
  const char **transfers,
  bool refunded,
  const char **refunds,
  const char **forgets,
  unsigned int http_status);


/**
 * Define a GET /private/orders/$ORDER_ID CMD.
 *
 * @param label the command label
 * @param merchant_url base URL of the merchant which will
 *        serve the request.
 * @param order_reference reference to a command that created an order.
 * @param osc expected order status
 * @param session_id session ID the payment must be bound to
 * @param repurchase_order_ref command of a paid equivalent order the merchant should be referring us to, or NULL
 * @param expected_http_status expected HTTP response code for the request.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_order3 (
  const char *label,
  const char *merchant_url,
  const char *order_reference,
  enum TALER_MERCHANT_OrderStatusCode osc,
  const char *session_id,
  const char *repurchase_order_ref,
  unsigned int expected_http_status);


/**
 * Define a GET /private/orders/$ORDER_ID CMD.
 *
 * @param label the command label
 * @param merchant_url base URL of the merchant which will
 *        serve the request.
 * @param order_reference reference to a command that created an order.
 * @param osc expected order status
 * @param expected_min_age expected minimum age for the contract
 * @param expected_http_status expected HTTP response code for the request.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_order4 (
  const char *label,
  const char *merchant_url,
  const char *order_reference,
  enum TALER_MERCHANT_OrderStatusCode osc,
  uint32_t expected_min_age,
  unsigned int expected_http_status);


/**
 * Start a long poll for GET /private/orders/$ORDER_ID.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_poll_order_start (const char *label,
                                    const char *merchant_url,
                                    const char *order_id,
                                    struct GNUNET_TIME_Relative timeout);


/**
 * Complete a long poll for GET /private/orders/$ORDER_ID.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_poll_order_conclude (const char *label,
                                       unsigned int http_status,
                                       const char *poll_start_reference);

/**
 * Make a "claim order" command.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant backend
 *        serving the proposal lookup request.
 * @param http_status expected HTTP response code.
 * @param order_reference reference to a POST order CMD, can be NULL if @a order_id given
 * @param order_id order id to lookup, can be NULL (then we use @a order_reference)
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_claim_order (const char *label,
                                        const char *merchant_url,
                                        unsigned int http_status,
                                        const char *order_reference,
                                        const char *order_id);


/**
 * Make a "pay" test command.
 *
 * @param label command label.
 * @param merchant_url merchant base url
 * @param http_status expected HTTP response code.
 * @param proposal_reference the proposal whose payment status
 *        is going to be checked.
 * @param coin_reference reference to any command which is able
 *        to provide coins to use for paying.
 * @param amount_with_fee amount to pay, including the deposit
 *        fee
 * @param amount_without_fee amount to pay, no fees included.
 * @param session_id the session id to use for the payment (can be NULL).
 * @return the command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_pay_order (
  const char *label,
  const char *merchant_url,
  unsigned int http_status,
  const char *proposal_reference,
  const char *coin_reference,
  const char *amount_with_fee,
  const char *amount_without_fee,
  const char *session_id);


/**
 * Make a "pay" test command for an order with choices.
 *
 * @param label command label.
 * @param merchant_url merchant base url
 * @param http_status expected HTTP response code.
 * @param proposal_reference the proposal whose payment status
 *        is going to be checked.
 * @param coin_reference reference to any command which is able
 *        to provide coins to use for paying.
 * @param amount_with_fee amount to pay, including the deposit
 *        fee
 * @param amount_without_fee amount to pay, no fees included.
 * @param session_id the session id to use for the payment (can be NULL).
 * @param choice_index index of the selected choice for the payment.
 * @param input_reference reference to a previous pay command that issued some
          outputs to be used as inputs to this pay request.
 * @return the command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_pay_order_choices (
  const char *label,
  const char *merchant_url,
  unsigned int http_status,
  const char *proposal_reference,
  const char *coin_reference,
  const char *amount_with_fee,
  const char *amount_without_fee,
  const char *session_id,
  int choice_index,
  const char *input_reference);

#ifdef HAVE_DONAU_DONAU_SERVICE_H

/**
 * Make a "pay" test command for an order with choices.
 *
 * @param label command label.
 * @param merchant_url merchant base url
 * @param http_status expected HTTP response code.
 * @param proposal_reference the proposal whose payment status
 *        is going to be checked.
 * @param coin_reference reference to any command which is able
 *        to provide coins to use for paying.
 * @param amount_with_fee amount to pay, including the deposit
 *        fee
 * @param amount_without_fee amount to pay, no fees included.
 * @param amount_donation amount for which the BKPS will be received.
 * @param session_id the session id to use for the payment (can be NULL).
 * @param choice_index index of the selected choice for the payment.
 * @param year year of the donation
 * @param donor_tax_id tax ID of the donor
 * @param salt salt for the donation
 * @return the command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_pay_order_donau (
  const char *label,
  const char *merchant_url,
  unsigned int http_status,
  const char *proposal_reference,
  const char *coin_reference,
  const char *amount_with_fee,
  const char *amount_without_fee,
  const char *amount_donation,
  const char *session_id,
  int choice_index,
  const char *charity_reference,
  uint64_t year,
  const char *donor_tax_id,
  const char *salt);

#endif

/**
 * Make an "order paid" test command.
 *
 * @param label command label
 * @param merchant_url merchant base URL
 * @param pay_reference reference to the payment to verify
 * @param session_id the session to use for the verification.
 * @param http_status expected HTTP response code
 * @return the command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_orders_paid (
  const char *label,
  const char *merchant_url,
  const char *pay_reference,
  const char *session_id,
  unsigned int http_status);


/**
 * Make an "abort" test command.
 *
 * @param label command label
 * @param merchant_url merchant base URL
 * @param pay_reference reference to the payment to abort
 * @param http_status expected HTTP response code
 * @return the command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_order_abort (
  const char *label,
  const char *merchant_url,
  const char *pay_reference,
  unsigned int http_status);


/**
 * Make a "order forget" command.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant backend
 *        serving the order claim request.
 * @param http_status expected HTTP response code.
 * @param order_reference reference to a POST order CMD, can be NULL if @a order_id given
 * @param order_id order id to forget for, can be NULL (then we use @a order_reference)
 * @param ... NULL-terminated list of paths (const char *) to forget in
 *        the contract terms.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_forget_order (
  const char *label,
  const char *merchant_url,
  unsigned int http_status,
  const char *order_reference,
  const char *order_id,
  ...);


/**
 * Define a "refund" order CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the backend serving the
 *        "refund increase" request.
 * @param reason refund justification, human-readable.
 * @param order_id order id of the contract to refund.
 * @param refund_amount amount to be refund-increased.
 * @param http_code expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_order_refund (
  const char *label,
  const char *merchant_url,
  const char *reason,
  const char *order_id,
  const char *refund_amount,
  unsigned int http_code);


/**
 * Define a "refund order" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the backend serving the
 *        "refund increase" request.
 * @param order_ref order id of the contract to refund.
 * @param http_code expected HTTP response code.
 * @param ... NULL-terminated list of labels (const char *) of
 *        refunds (commands) we expect to be aggregated in the transfer
 *        (assuming @a http_code is #MHD_HTTP_OK). If @e refunded is false,
 *        this parameter is ignored.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_wallet_order_refund (
  const char *label,
  const char *merchant_url,
  const char *order_ref,
  unsigned int http_code,
  ...);


/**
 * Define a "DELETE order" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        DELETE /instances/$ID request.
 * @param order_id the ID of the instance to query
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_order (
  const char *label,
  const char *merchant_url,
  const char *order_id,
  unsigned int http_status);


/* ******************* /transfers *************** */


/**
 * Define a POST /transfers CMD.  Details like the WTID and
 * other required parameters will be extracted from the bank
 * history, using the latest transfer of the specified
 * @a credit_amount to the @a merchant_url.
 *
 * @param label command label.
 * @param auth credentials to access the exchange's bank account
 * @param payto_uri URL of the exchange's bank account
 * @param merchant_url base URL of the backend serving the
 *        "refund increase" request.
 * @param credit_amount amount credited
 * @param http_code expected HTTP response code
 * @param ... NULL-terminated list of labels (const char *) of
 *        deposit (commands) we expect to be aggregated in the transfer
 *        (assuming @a http_code is #MHD_HTTP_OK)
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_transfer (
  const char *label,
  const struct TALER_BANK_AuthenticationData *auth,
  struct TALER_FullPayto payto_uri,
  const char *merchant_url,
  const char *credit_amount,
  unsigned int http_code,
  ...);


/**
 * Define a POST /transfers CMD.  Details like the WTID and
 * other required parameters are explicitly provided.
 *
 * @param label command label.
 * @param merchant_url base URL of the backend
 * @param payto_uri URL of the exchange's bank account
 * @param credit_amount amount credited
 * @param wtid wire transfer ID to use, NULL to pick one at random
 * @param exchange_url URL of the exchange to use
 * @param http_code expected HTTP response code
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_transfer2 (
  const char *label,
  const char *merchant_url,
  struct TALER_FullPayto payto_uri,
  const char *credit_amount,
  const char *wtid,
  const char *exchange_url,
  unsigned int http_code);


/**
 * We have discovered the @a serial for a POST transfer
 * command. Store it (for the bank row trait).
 *
 * @param cmd command to update
 * @param serial serial number to store (identifies the row)
 */
void
TALER_TESTING_cmd_merchant_post_transfer_set_serial (
  struct TALER_TESTING_Command *cmd,
  uint64_t serial);


/**
 * Define a GET /transfers CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the backend serving the
 *        "refund increase" request.
 * @param payto_uri payto URI to filter by, NULL for no filter
 * @param http_code expected HTTP response code
 * @param ... NULL-terminated list of labels (const char *) of
 *        transfer (commands) we expect to be returned in the list
 *        (assuming @a http_code is #MHD_HTTP_OK)
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_transfers (
  const char *label,
  const char *merchant_url,
  struct TALER_FullPayto payto_uri,
  unsigned int http_code,
  ...);


/**
 * Define a "DELETE transfer" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant for the
 *        DELETE /transfers/$ID request.
 * @param transfer_ref reference to a command that
 *             yields the transfer ID to delete
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_transfer (const char *label,
                                            const char *merchant_url,
                                            const char *transfer_ref,
                                            unsigned int http_status);


/**
 * Run a command to fetch the KYC status of a merchant.
 *
 * @param label the command label
 * @param merchant_url base URL of the merchant
 * @param instance_id instance to use, NULL if instance is part of @a merchant_url
 * @param h_wire_ref label of command with a merchant wire hash trait
 *        of the bank account to check KYC for; NULL to check all accounts
 * @param exchange_url base URL of the exchange to check KYC status for
 * @param lpt target for long polling
 * @param expected_http_status expected HTTP status
 * @param expected_kyc_state expected KYC state (only effective if @e expected_http_status is #MHD_HTTP_OK/#MHD_HTTP_ACCEPTED)
 * @return the command
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_kyc_get (
  const char *label,
  const char *merchant_url,
  const char *instance_id,
  const char *h_wire_ref,
  const char *exchange_url,
  enum TALER_EXCHANGE_KycLongPollTarget lpt,
  unsigned int expected_http_status,
  bool expected_kyc_state);


/* ****** OTP devices ******* */


/**
 * Define a "POST /otp-devices" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /otps request.
 * @param otp_id the ID of the otp device to modify
 * @param otp_description description of the otp device
 * @param otp_key base32-encoded key to verify the payment
 * @param otp_alg is an option that show the amount of the order. it is linked with the @a otp_key
 * @param otp_ctr counter to use (if in counter mode)
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_otp_devices (
  const char *label,
  const char *merchant_url,
  const char *otp_id,
  const char *otp_description,
  const char *otp_key,
  enum TALER_MerchantConfirmationAlgorithm otp_alg,
  uint64_t otp_ctr,
  unsigned int http_status);


/**
 * Define a "PATCH /otp-devices/$ID" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        PATCH /otp-devices request.
 * @param otp_id the ID of the otp device to modify
 * @param otp_description description of the otp device
 * @param otp_key base32-encoded key to verify the payment
 * @param otp_alg is an option that show the amount of the order. it is linked with the @a otp_key
 * @param otp_ctr counter to use (if in counter mode)
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_patch_otp_device (
  const char *label,
  const char *merchant_url,
  const char *otp_id,
  const char *otp_description,
  const char *otp_key,
  enum TALER_MerchantConfirmationAlgorithm otp_alg,
  uint64_t otp_ctr,
  unsigned int http_status);


/**
 * Define a "GET /otp-devices" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        GET /otp-devices request.
 * @param http_status expected HTTP response code.
 * @param ... NULL-terminated list of labels (const char *) of
 *        otp (commands) we expect to be returned in the list
 *        (assuming @a http_code is #MHD_HTTP_OK)
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_otp_devices (const char *label,
                                            const char *merchant_url,
                                            unsigned int http_status,
                                            ...);


/**
 * Define a "GET otp device" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        GET /otp-devices/$ID request.
 * @param otp_id the ID of the otp to query
 * @param http_status expected HTTP response code.
 * @param otp_reference reference to a "POST /otp-devices" or "PATCH /otp-devices/$ID" CMD
 *        that will provide what we expect the backend to return to us
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_otp_device (const char *label,
                                           const char *merchant_url,
                                           const char *otp_id,
                                           unsigned int http_status,
                                           const char *otp_reference);


/**
 * Define a "DELETE otp device" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        DELETE /otp-devices/$ID request.
 * @param otp_id the ID of the otp to query
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_otp_device (const char *label,
                                              const char *merchant_url,
                                              const char *otp_id,
                                              unsigned int http_status);


/* ****** Templates ******* */

/**
 * Define a "POST /units" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the request.
 * @param unit_id identifier of the unit.
 * @param unit_name_long long label to store.
 * @param unit_name_short short label to store.
 * @param unit_allow_fraction whether fractional quantities are allowed.
 * @param unit_precision_level fractional precision level.
 * @param unit_active whether the unit starts active.
 * @param unit_name_long_i18n optional translations for the long label.
 * @param unit_name_short_i18n optional translations for the short label.
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_units (const char *label,
                                       const char *merchant_url,
                                       const char *unit_id,
                                       const char *unit_name_long,
                                       const char *unit_name_short,
                                       bool unit_allow_fraction,
                                       uint32_t unit_precision_level,
                                       bool unit_active,
                                       json_t *unit_name_long_i18n,
                                       json_t *unit_name_short_i18n,
                                       unsigned int http_status);


/**
 * Define a "PATCH /units/$ID" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the request.
 * @param unit_id identifier of the unit to patch.
 * @param unit_name_long optional new long label (NULL to skip).
 * @param unit_name_short optional new short label (NULL to skip).
 * @param unit_name_long_i18n optional new long label translations (NULL to skip).
 * @param unit_name_short_i18n optional new short label translations (NULL to skip).
 * @param unit_allow_fraction optional pointer to new fractional flag (NULL to skip).
 * @param unit_precision_level optional pointer to new precision level (NULL to skip).
 * @param unit_active optional pointer to new active flag (NULL to skip).
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_patch_unit (
  const char *label,
  const char *merchant_url,
  const char *unit_id,
  const char *unit_name_long,
  const char *unit_name_short,
  json_t *unit_name_long_i18n,
  json_t *unit_name_short_i18n,
  const bool unit_allow_fraction,
  const uint32_t unit_precision_level,
  const bool unit_active,
  unsigned int http_status);


/**
 * Define a "GET /units" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the request.
 * @param http_status expected HTTP response code.
 * @param ... NULL-terminated list of labels (const char *) whose units must
 *        appear in the response (verified when @a http_status is #MHD_HTTP_OK).
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_units (const char *label,
                                      const char *merchant_url,
                                      unsigned int http_status,
                                      ...);


/**
 * Define a "GET /units/$ID" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the request.
 * @param unit_id identifier to fetch.
 * @param http_status expected HTTP response code.
 * @param reference optional label of a command providing expected unit traits.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_unit (const char *label,
                                     const char *merchant_url,
                                     const char *unit_id,
                                     unsigned int http_status,
                                     const char *reference);


/**
 * Define a "DELETE /units/$ID" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the request.
 * @param unit_id identifier to delete.
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_unit (const char *label,
                                        const char *merchant_url,
                                        const char *unit_id,
                                        unsigned int http_status);


/**
 * Define a "POST /templates" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /templates request.
 * @param template_id the ID of the template to query
 * @param template_description description of the template
 * @param otp_id OTP device ID, NULL for none
 * @param template_contract where the contract of the company is
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_templates2 (
  const char *label,
  const char *merchant_url,
  const char *template_id,
  const char *template_description,
  const char *otp_id,
  json_t *template_contract,
  unsigned int http_status);


/**
 * Define a "POST /templates" CMD, simple version
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /templates request.
 * @param template_id the ID of the template to create
 * @param template_description description of the template
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_templates (const char *label,
                                           const char *merchant_url,
                                           const char *template_id,
                                           const char *template_description,
                                           unsigned int http_status);


/**
 * Define a "PATCH /templates/$ID" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        PATCH /template request.
 * @param template_id the ID of the template to query
 * @param template_description description of the template
 * @param otp_id OTP device to use
 * @param template_contract contract of the company
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_patch_template (
  const char *label,
  const char *merchant_url,
  const char *template_id,
  const char *template_description,
  const char *otp_id,
  json_t *template_contract,
  unsigned int http_status);


/**
 * Define a "GET /templates" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        GET /templates request.
 * @param http_status expected HTTP response code.
 * @param ... NULL-terminated list of labels (const char *) of
 *        template (commands) we expect to be returned in the list
 *        (assuming @a http_code is #MHD_HTTP_OK)
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_templates (const char *label,
                                          const char *merchant_url,
                                          unsigned int http_status,
                                          ...);


/**
 * Define a "GET template" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        GET /templates/$ID request.
 * @param template_id the ID of the template to query
 * @param http_status expected HTTP response code.
 * @param template_reference reference to a "POST /templates" or "PATCH /templates/$ID" CMD
 *        that will provide what we expect the backend to return to us
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_template (const char *label,
                                         const char *merchant_url,
                                         const char *template_id,
                                         unsigned int http_status,
                                         const char *template_reference);


/**
 * Define a "DELETE template" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        DELETE /templates/$ID request.
 * @param template_id the ID of the template to query
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_template (const char *label,
                                            const char *merchant_url,
                                            const char *template_id,
                                            unsigned int http_status);


/**
 * Define a "POST /using-templates" CMD, simple version
 *
 * @param label command label.
 * @param template_ref label of command that created the template to use
 * @param otp_ref label of command that created OTP device we use (or NULL for no OTP)
 * @param merchant_url base URL of the merchant serving the
 *        POST /using-templates request.
 * @param using_template_id template ID to use
 * @param summary given by the customer to know what they did pay
 * @param amount given by the customer to pay
 * @param refund_deadline refund deadline to use for the contract
 * @param pay_deadline pay deadline to use for the contract
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_using_templates (
  const char *label,
  const char *template_ref,
  const char *otp_ref,
  const char *merchant_url,
  const char *using_template_id,
  const char *summary,
  const char *amount,
  struct GNUNET_TIME_Timestamp refund_deadline,
  struct GNUNET_TIME_Timestamp pay_deadline,
  unsigned int http_status);


/* ****** Token Families ******* */


/**
 * Define a "POST /tokenfamilies" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *       POST /tokenfamilies request.
 * @param http_status expected HTTP response code.
 * @param slug slug of the token family.
 * @param name name of the token family.
 * @param description description of the token family.
 * @param description_i18n internationalized description of the token family.
 * @param valid_after start of the validity time of the token family.
 * @param valid_before end of the validity time of the token family.
 * @param duration validity duration of an issued token of the token family.
 * @param rounding to multiples of what duration should start times be rounded
 * @param kind kind of the token family. either "subscription" or "discount".
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_tokenfamilies (
  const char *label,
  const char *merchant_url,
  unsigned int http_status,
  const char *slug,
  const char *name,
  const char *description,
  json_t *description_i18n,
  struct GNUNET_TIME_Timestamp valid_after,
  struct GNUNET_TIME_Timestamp valid_before,
  struct GNUNET_TIME_Relative duration,
  struct GNUNET_TIME_Relative rounding,
  const char *kind);

/* ****** Webhooks ******* */


/**
 * Define a "POST /webhooks" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /webhooks request.
 * @param webhook_id the ID of the webhook to query
 * @param event_type event of the webhook
 * @param url use by the customer
 * @param http_method use by the merchant
 * @param header_template of the webhook
 * @param body_template of the webhook
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_webhooks2 (
  const char *label,
  const char *merchant_url,
  const char *webhook_id,
  const char *event_type,
  const char *url,
  const char *http_method,
  const char *header_template,
  const char *body_template,
  unsigned int http_status);


/**
 * Define a "POST /webhooks" CMD, simple version
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        POST /webhooks request.
 * @param webhook_id the ID of the webhook to query
 * @param event_type event of the webhook
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_webhooks (const char *label,
                                          const char *merchant_url,
                                          const char *webhook_id,
                                          const char *event_type,
                                          unsigned int http_status);


/**
 * Define a "PATCH /webhooks/$ID" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        PATCH /webhook request.
 * @param webhook_id the ID of the webhook to query
 * @param event_type event of the webhook
 * @param url use by the customer
 * @param http_method use by the merchant
 * @param header_template of the webhook
 * @param body_template of the webhook
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_patch_webhook (
  const char *label,
  const char *merchant_url,
  const char *webhook_id,
  const char *event_type,
  const char *url,
  const char *http_method,
  const char *header_template,
  const char *body_template,
  unsigned int http_status);


/**
 * Define a "GET /webhooks" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        GET /webhooks request.
 * @param http_status expected HTTP response code.
 * @param ... NULL-terminated list of labels (const char *) of
 *        webhook (commands) we expect to be returned in the list
 *        (assuming @a http_code is #MHD_HTTP_OK)
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_webhooks (const char *label,
                                         const char *merchant_url,
                                         unsigned int http_status,
                                         ...);


/**
 * Define a "GET webhook" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        GET /templates/$ID request.
 * @param webhook_id the ID of the webhook to query
 * @param http_status expected HTTP response code.
 * @param webhook_reference reference to a "POST /webhooks" or "PATCH /webhooks/$ID" CMD
 *        that will provide what we expect the backend to return to us
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_webhook (const char *label,
                                        const char *merchant_url,
                                        const char *webhook_id,
                                        unsigned int http_status,
                                        const char *webhook_reference);


/**
 * Define a "DELETE webhook" CMD.
 *
 * @param label command label.
 * @param merchant_url base URL of the merchant serving the
 *        DELETE /webhooks/$ID request.
 * @param webhook_id the ID of the webhook to query
 * @param http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_webhook (const char *label,
                                           const char *merchant_url,
                                           const char *webhook_id,
                                           unsigned int http_status);

/**
 * Command to run the 'taler-merchant-webhook' program.
 *
 * @param label command label.
 * @param config_filename configuration file used by the webhook.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_webhook (const char *label,
                           const char *config_filename);


/**
 * Command to run the 'taler-merchant-depositcheck' program.
 *
 * @param label command label.
 * @param config_filename configuration file used by the deposit check helper.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_depositcheck (const char *label,
                                const char *config_filename);


/**
 * Command to run the 'taler-merchant-exchange' program.
 *
 * @param label command label.
 * @param config_filename configuration file used by the webhook.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_run_tme (const char *label,
                           const char *config_filename);


/**
 * This function is used to start the web server.
 *
 * @param label command label
 * @param port is the port of the web server
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_testserver (const char *label,
                              uint16_t port);


/**
 * This function is used to check the web server got the
 * expected request from the web hook.
 *
 * @param label command label
 * @param ref_operation reference to command to the previous set server status operation.
 * @param index index to know which web server we check.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_checkserver (const char *label,
                               const char *ref_operation,
                               unsigned int index);


/**
 * This function is used to check that the web server
 * got the expected request from the web hook.
 *
 * @param label command label
 * @param ref_operation reference to command to the previous set server status operation.
 * @param index index to know which web server we check.
 * @param expected_url url of the webhook
 * @param expected_method method of the webhook
 * @param expected_header header of the webhook
 * @param expected_body body of the webhook
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_checkserver2 (const char *label,
                                const char *ref_operation,
                                unsigned int index,
                                const char *expected_url,
                                const char *expected_method,
                                const char *expected_header,
                                const char *expected_body);


#ifdef HAVE_DONAU_DONAU_SERVICE_H
/**
 * This function is the similar to the TALER_TESSTING_cmd_charity_post from DONAU
 * with only difference that it reuses the merchant public key, from the merchant test-suite.
 *
 * @param label command label
 * @param name name of the charity
 * @param url url of the charity
 * @param max_per_year maximum amount of donations per year
 * @param bearer
 * @param merchant_reference reference to fetch the merchant public key
 * @param expected_response_code expected HTTP response code
 * @return
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_charity_post_merchant (
  const char *label,
  const char *name,
  const char *url,
  const char *max_per_year,
  const struct DONAU_BearerToken *bearer,
  const char *merchant_reference,
  unsigned int expected_response_code);

#endif /* HAVE_DONAU_DONAU_SERVICE_H */

/**
 * Define a "GET /donau" CMD.
 *
 * @param label command label.
 * @param url base URL of the Donau we are looking for instances of.
 * @param instance_count number of instances we expect to be returned.
 * @param expected_http_status expected HTTP response code.
 * @param ... NULL-terminated list of labels (const char *) of
 *        donau instances (commands) we expect to be returned in the list
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_donau_instances (const char *label,
                                                const char *url,
                                                unsigned int instance_count,
                                                unsigned int
                                                expected_http_status,
                                                ...);


/**
 * Define a "POST /donau" CMD.
 *
 * @param label command label.
 * @param url base URL of the Donau service serving the
 *        GET /donau_instances request.
 * @param merchant_reference string reference to get the testing traits
 * @param expected_http_status expected HTTP response code.
 * @param ... NULL-terminated list of labels (const char *) of
 *        donau instances (commands) we expect to be returned in the list
 *        (assuming @a expected_http_status is #MHD_HTTP_OK)
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_post_donau_instance (const char *label,
                                                const char *url,
                                                const char *merchant_reference,
                                                unsigned int
                                                expected_http_status,
                                                ...);


/**
 * Define a "DELETE /donau/$charity_id" CMD.
 *
 * @param label command label.
 * @param url base URL of the Donau service serving the
 *        DELETE /donau/$charity_id request.
 * @param charity_id the ID of the charity to delete.
 * @param expected_http_status expected HTTP response code.
 * @return the command.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_delete_donau_instance (const char *label,
                                                  const char *url,
                                                  uint64_t charity_id,
                                                  unsigned int
                                                  expected_http_status);

/**
 * This function is used to check the statistics counter API
 *
 * @param label command label
 * @param merchant_url base URL of the merchant serving the API
 * @param slug base statistics slug
 * @param buckets_length expected length of buckets array
 * @param intervals_length expected length of intervals array
 * @param http_status expected HTTP response code.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_statisticscounter (const char *label,
                                                  const char *merchant_url,
                                                  const char *slug,
                                                  uint64_t buckets_length,
                                                  uint64_t intervals_length,
                                                  unsigned int http_status);

/**
 * This function is used to check the statistics amount API
 *
 * @param label command label
 * @param merchant_url base URL of the merchant serving the API
 * @param slug base statistics slug
 * @param buckets_length expected length of buckets array
 * @param intervals_length expected length of intervals array
 * @param http_status expected HTTP response code.
 */
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_get_statisticsamount (const char *label,
                                                 const char *merchant_url,
                                                 const char *slug,
                                                 uint64_t buckets_length,
                                                 uint64_t intervals_length,
                                                 unsigned int http_status);

/* ****** Specific traits supported by this component ******* */


/**
 * Call @a op on all simple traits.
 *
 * @param op macro to call
 */
// FIXME: rename: refund_entry->refund_detail
#define TALER_MERCHANT_TESTING_SIMPLE_TRAITS(op) \
  op (claim_nonce, const struct GNUNET_CRYPTO_EddsaPublicKey) \
  op (pickup_id, const struct TALER_PickupIdentifierP) \
  op (instance_name, const char) \
  op (instance_id, const char) \
  op (address, const json_t) \
  op (product_description, const char) \
  op (product_image, const char) \
  op (product_stock, const int64_t) \
  op (product_unit_total_stock, const char) \
  op (product_unit_precision_level, const uint32_t) \
  op (product_unit_allow_fraction, const bool) \
  op (product_unit, const char) \
  op (product_id, const char) \
  op (unit_id, const char) \
  op (unit_name_long, const char) \
  op (unit_name_short, const char) \
  op (unit_allow_fraction, const bool) \
  op (unit_precision_level, const uint32_t) \
  op (unit_active, const bool) \
  op (unit_builtin, const bool) \
  op (unit_name_long_i18n, const json_t) \
  op (unit_name_short_i18n, const json_t) \
  op (reason, const char) \
  op (lock_uuid, const char) \
  op (auth_token, const char) \
  op (bearer_token, const char) \
  op (paths_length, const uint32_t) \
  op (payto_length, const uint32_t) \
  op (num_planchets, const uint32_t) \
  op (i18n_description, const json_t) \
  op (taxes, const json_t)      \
  op (fee, const struct TALER_Amount) \
  op (use_stefan, const bool) \
  op (jurisdiction, const json_t) \
  op (wire_delay, const struct GNUNET_TIME_Relative) \
  op (pay_delay, const struct GNUNET_TIME_Relative) \
  op (refund_entry, const struct TALER_MERCHANT_RefundDetail) \
  op (order_terms, const json_t) \
  op (h_contract_terms, const struct TALER_PrivateContractHashP) \
  op (h_wire, const struct TALER_MerchantWireHashP) \
  op (proposal_reference, const char) \
  op (template_description, const char) \
  op (otp_device_description, const char) \
  op (otp_id, const char) \
  op (otp_key, const char) \
  op (otp_alg, const enum TALER_MerchantConfirmationAlgorithm) \
  op (template_id, const char) \
  op (template_contract, const json_t) \
  op (event_type, const char)   \
  op (webhook_id, const char) \
  op (merchant_base_url, const char) \
  op (url, const char) \
  op (http_method, const char)   \
  op (header_template, const char)   \
  op (body_template, const char)   \
  op (summary, const char)   \
  op (token_family_slug, const char)   \
  op (token_family_duration, const struct GNUNET_TIME_Relative)   \
  op (token_family_kind, const char)


/**
 * Call @a op on all indexed traits.
 *
 * @param op macro to call
 */
#define TALER_MERCHANT_TESTING_INDEXED_TRAITS(op) \
  op (coin_reference, const char) \
  op (paths, const char) \
  op (payto_uris, const struct TALER_FullPayto) \
  op (h_wires, const struct TALER_MerchantWireHashP) \
  op (amounts, const struct TALER_Amount)         \
  op (urls, const char) \
  op (http_methods, const char)   \
  op (http_header, const char)   \
  op (http_body, const void)   \
  op (http_body_size, const size_t)   \
  op (planchet_secrets, const struct TALER_PlanchetMasterSecretP)   \
  op (token_priv, const struct TALER_TokenUsePrivateKeyP)   \
  op (token_issue_sig, const struct TALER_TokenIssueSignature)   \
  op (token_issue_pub, const struct TALER_TokenIssuePublicKey)


TALER_MERCHANT_TESTING_SIMPLE_TRAITS (TALER_TESTING_MAKE_DECL_SIMPLE_TRAIT)
TALER_MERCHANT_TESTING_INDEXED_TRAITS (TALER_TESTING_MAKE_DECL_INDEXED_TRAIT)


#endif
