Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2021 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as
7 : published by the Free Software Foundation; either version 3, or
8 : (at your option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with TALER; see the file COPYING. If not, see
17 : <http://www.gnu.org/licenses/>
18 : */
19 :
20 : /**
21 : * @file testing_api_cmd_post_orders.c
22 : * @brief command to run POST /orders
23 : * @author Marcello Stanisci
24 : */
25 :
26 : #include "platform.h"
27 : #include <taler/taler_exchange_service.h>
28 : #include <taler/taler_testing_lib.h>
29 : #include "taler_merchant_service.h"
30 : #include "taler_merchant_testing_lib.h"
31 :
32 : /**
33 : * State for a "POST /orders" CMD.
34 : */
35 : struct OrdersState
36 : {
37 :
38 : /**
39 : * Expected status code.
40 : */
41 : unsigned int http_status;
42 :
43 : /**
44 : * Order id.
45 : */
46 : const char *order_id;
47 :
48 : /**
49 : * The order id we expect the merchant to assign (if not NULL).
50 : */
51 : const char *expected_order_id;
52 :
53 : /**
54 : * Contract terms obtained from the backend.
55 : */
56 : json_t *contract_terms;
57 :
58 : /**
59 : * Order submitted to the backend.
60 : */
61 : json_t *order_terms;
62 :
63 : /**
64 : * Contract terms hash code.
65 : */
66 : struct TALER_PrivateContractHashP h_contract_terms;
67 :
68 : /**
69 : * The /orders operation handle.
70 : */
71 : struct TALER_MERCHANT_PostOrdersHandle *po;
72 :
73 : /**
74 : * The (initial) POST /orders/$ID/claim operation handle.
75 : * The logic is such that after an order creation,
76 : * we immediately claim the order.
77 : */
78 : struct TALER_MERCHANT_OrderClaimHandle *och;
79 :
80 : /**
81 : * The nonce.
82 : */
83 : struct GNUNET_CRYPTO_EddsaPublicKey nonce;
84 :
85 : /**
86 : * Whether to generate a claim token.
87 : */
88 : bool make_claim_token;
89 :
90 : /**
91 : * The claim token
92 : */
93 : struct TALER_ClaimTokenP claim_token;
94 :
95 : /**
96 : * URL of the merchant backend.
97 : */
98 : const char *merchant_url;
99 :
100 : /**
101 : * The interpreter state.
102 : */
103 : struct TALER_TESTING_Interpreter *is;
104 :
105 : /**
106 : * Merchant signature over the orders.
107 : */
108 : struct TALER_MerchantSignatureP merchant_sig;
109 :
110 : /**
111 : * Merchant public key.
112 : */
113 : struct TALER_MerchantPublicKeyP merchant_pub;
114 :
115 : /**
116 : * The payment target for the order
117 : */
118 : const char *payment_target;
119 :
120 : /**
121 : * The products the order is purchasing.
122 : */
123 : const char *products;
124 :
125 : /**
126 : * The locks that the order should release.
127 : */
128 : const char *locks;
129 :
130 : /**
131 : * Should the command also CLAIM the order?
132 : */
133 : bool with_claim;
134 :
135 : /**
136 : * If not NULL, the command should duplicate the request and verify the
137 : * response is the same as in this command.
138 : */
139 : const char *duplicate_of;
140 : };
141 :
142 :
143 : /**
144 : * Offer internal data to other commands.
145 : *
146 : * @param cls closure
147 : * @param[out] ret result (could be anything)
148 : * @param trait name of the trait
149 : * @param index index number of the object to extract.
150 : * @return #GNUNET_OK on success
151 : */
152 : static enum GNUNET_GenericReturnValue
153 0 : orders_traits (void *cls,
154 : const void **ret,
155 : const char *trait,
156 : unsigned int index)
157 : {
158 0 : struct OrdersState *ps = cls;
159 : struct TALER_TESTING_Trait traits[] = {
160 0 : TALER_TESTING_make_trait_order_id (&ps->order_id),
161 0 : TALER_TESTING_make_trait_contract_terms (ps->contract_terms),
162 0 : TALER_TESTING_make_trait_order_terms (ps->order_terms),
163 0 : TALER_TESTING_make_trait_h_contract_terms (&ps->h_contract_terms),
164 0 : TALER_TESTING_make_trait_merchant_sig (&ps->merchant_sig),
165 0 : TALER_TESTING_make_trait_merchant_pub (&ps->merchant_pub),
166 0 : TALER_TESTING_make_trait_claim_nonce (&ps->nonce),
167 0 : TALER_TESTING_make_trait_claim_token (&ps->claim_token),
168 0 : TALER_TESTING_trait_end ()
169 : };
170 :
171 0 : return TALER_TESTING_get_trait (traits,
172 : ret,
173 : trait,
174 : index);
175 : }
176 :
177 :
178 : /**
179 : * Used to fill the "orders" CMD state with backend-provided
180 : * values. Also double-checks that the order was correctly
181 : * created.
182 : *
183 : * @param cls closure
184 : * @param hr HTTP response we got
185 : * @param contract_terms contract terms of this order
186 : * @param sig merchant's signature
187 : * @param hash hash over the contract
188 : */
189 : static void
190 0 : orders_claim_cb (void *cls,
191 : const struct TALER_MERCHANT_HttpResponse *hr,
192 : const json_t *contract_terms,
193 : const struct TALER_MerchantSignatureP *sig,
194 : const struct TALER_PrivateContractHashP *hash)
195 : {
196 0 : struct OrdersState *ps = cls;
197 : struct TALER_MerchantPublicKeyP merchant_pub;
198 : const char *error_name;
199 : unsigned int error_line;
200 : struct GNUNET_JSON_Specification spec[] = {
201 0 : GNUNET_JSON_spec_fixed_auto ("merchant_pub",
202 : &merchant_pub),
203 0 : GNUNET_JSON_spec_end ()
204 : };
205 :
206 0 : ps->och = NULL;
207 0 : if (ps->http_status != hr->http_status)
208 0 : TALER_TESTING_FAIL (ps->is);
209 :
210 0 : ps->contract_terms = json_deep_copy (contract_terms);
211 0 : ps->h_contract_terms = *hash;
212 0 : ps->merchant_sig = *sig;
213 0 : if (GNUNET_OK !=
214 0 : GNUNET_JSON_parse (contract_terms,
215 : spec,
216 : &error_name,
217 : &error_line))
218 : {
219 : char *log;
220 :
221 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
222 : "Parser failed on %s:%u\n",
223 : error_name,
224 : error_line);
225 0 : log = json_dumps (ps->contract_terms,
226 : JSON_INDENT (1));
227 0 : fprintf (stderr,
228 : "%s\n",
229 : log);
230 0 : free (log);
231 0 : TALER_TESTING_FAIL (ps->is);
232 : }
233 0 : ps->merchant_pub = merchant_pub;
234 0 : TALER_TESTING_interpreter_next (ps->is);
235 : }
236 :
237 :
238 : /**
239 : * Callback that processes the response following a
240 : * POST /orders. NOTE: no contract terms are included
241 : * here; they need to be taken via the "orders lookup"
242 : * method.
243 : *
244 : * @param cls closure.
245 : * @param por details about the response
246 : */
247 : static void
248 0 : order_cb (void *cls,
249 : const struct TALER_MERCHANT_PostOrdersReply *por)
250 : {
251 0 : struct OrdersState *ps = cls;
252 :
253 0 : ps->po = NULL;
254 0 : if (ps->http_status != por->hr.http_status)
255 : {
256 0 : TALER_LOG_ERROR ("Given vs expected: %u(%d) vs %u\n",
257 : por->hr.http_status,
258 : (int) por->hr.ec,
259 : ps->http_status);
260 0 : TALER_TESTING_FAIL (ps->is);
261 : }
262 0 : if (0 == ps->http_status)
263 : {
264 0 : TALER_LOG_DEBUG ("/orders, expected 0 status code\n");
265 0 : TALER_TESTING_interpreter_next (ps->is);
266 0 : return;
267 : }
268 0 : switch (por->hr.http_status)
269 : {
270 0 : case MHD_HTTP_OK:
271 0 : if (NULL != por->details.ok.token)
272 0 : ps->claim_token = *por->details.ok.token;
273 0 : ps->order_id = GNUNET_strdup (por->details.ok.order_id);
274 0 : if ((NULL != ps->expected_order_id) &&
275 0 : (0 != strcmp (por->details.ok.order_id,
276 : ps->expected_order_id)))
277 : {
278 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
279 : "Order id assigned does not match\n");
280 0 : TALER_TESTING_interpreter_fail (ps->is);
281 0 : return;
282 : }
283 0 : if (NULL != ps->duplicate_of)
284 : {
285 : const struct TALER_TESTING_Command *order_cmd;
286 : const struct TALER_ClaimTokenP *prev_token;
287 0 : struct TALER_ClaimTokenP zero_token = {0};
288 :
289 0 : order_cmd = TALER_TESTING_interpreter_lookup_command (
290 : ps->is,
291 : ps->duplicate_of);
292 0 : if (GNUNET_OK !=
293 0 : TALER_TESTING_get_trait_claim_token (order_cmd,
294 : &prev_token))
295 : {
296 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
297 : "Could not fetch previous order claim token\n");
298 0 : TALER_TESTING_interpreter_fail (ps->is);
299 0 : return;
300 : }
301 0 : if (NULL == por->details.ok.token)
302 0 : prev_token = &zero_token;
303 0 : if (0 != GNUNET_memcmp (prev_token,
304 : por->details.ok.token))
305 : {
306 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
307 : "Claim tokens for identical requests do not match\n");
308 0 : TALER_TESTING_interpreter_fail (ps->is);
309 0 : return;
310 : }
311 : }
312 0 : break;
313 0 : case MHD_HTTP_NOT_FOUND:
314 0 : TALER_TESTING_interpreter_next (ps->is);
315 0 : return;
316 0 : case MHD_HTTP_GONE:
317 0 : TALER_TESTING_interpreter_next (ps->is);
318 0 : return;
319 0 : case MHD_HTTP_CONFLICT:
320 0 : TALER_TESTING_interpreter_next (ps->is);
321 0 : return;
322 0 : default:
323 : {
324 0 : char *s = json_dumps (por->hr.reply,
325 : JSON_COMPACT);
326 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
327 : "Unexpected status code from /orders: %u (%d) at %s; JSON: %s\n",
328 : por->hr.http_status,
329 : (int) por->hr.ec,
330 : TALER_TESTING_interpreter_get_current_label (ps->is),
331 : s);
332 0 : GNUNET_free (s);
333 : /**
334 : * Not failing, as test cases are _supposed_
335 : * to create non 200 OK situations.
336 : */
337 0 : TALER_TESTING_interpreter_next (ps->is);
338 : }
339 0 : return;
340 : }
341 :
342 0 : if (! ps->with_claim)
343 : {
344 0 : TALER_TESTING_interpreter_next (ps->is);
345 0 : return;
346 : }
347 0 : if (NULL ==
348 0 : (ps->och = TALER_MERCHANT_order_claim (ps->is->ctx,
349 : ps->merchant_url,
350 : ps->order_id,
351 0 : &ps->nonce,
352 0 : &ps->claim_token,
353 : &orders_claim_cb,
354 : ps)))
355 0 : TALER_TESTING_FAIL (ps->is);
356 : }
357 :
358 :
359 : /**
360 : * Run a "orders" CMD.
361 : *
362 : * @param cls closure.
363 : * @param cmd command currently being run.
364 : * @param is interpreter state.
365 : */
366 : static void
367 0 : orders_run (void *cls,
368 : const struct TALER_TESTING_Command *cmd,
369 : struct TALER_TESTING_Interpreter *is)
370 : {
371 0 : struct OrdersState *ps = cls;
372 :
373 0 : ps->is = is;
374 0 : if (NULL == json_object_get (ps->order_terms,
375 : "order_id"))
376 : {
377 : struct GNUNET_TIME_Absolute now;
378 : char *order_id;
379 :
380 0 : now = GNUNET_TIME_absolute_get_monotonic (is->cfg);
381 0 : order_id = GNUNET_STRINGS_data_to_string_alloc (
382 : &now,
383 : sizeof (now));
384 0 : GNUNET_assert (0 ==
385 : json_object_set_new (ps->order_terms,
386 : "order_id",
387 : json_string (order_id)));
388 0 : GNUNET_free (order_id);
389 : }
390 0 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
391 0 : &ps->nonce,
392 : sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
393 0 : ps->po = TALER_MERCHANT_orders_post (is->ctx,
394 : ps->merchant_url,
395 0 : ps->order_terms,
396 0 : GNUNET_TIME_UNIT_ZERO,
397 : &order_cb,
398 : ps);
399 0 : GNUNET_assert (NULL != ps->po);
400 0 : }
401 :
402 :
403 : /**
404 : * Run a "orders" CMD.
405 : *
406 : * @param cls closure.
407 : * @param cmd command currently being run.
408 : * @param is interpreter state.
409 : */
410 : static void
411 0 : orders_run2 (void *cls,
412 : const struct TALER_TESTING_Command *cmd,
413 : struct TALER_TESTING_Interpreter *is)
414 : {
415 0 : struct OrdersState *ps = cls;
416 : const json_t *order;
417 0 : char *products_string = GNUNET_strdup (ps->products);
418 0 : char *locks_string = GNUNET_strdup (ps->locks);
419 : char *token;
420 0 : struct TALER_MERCHANT_InventoryProduct *products = NULL;
421 0 : unsigned int products_length = 0;
422 0 : const char **locks = NULL;
423 0 : unsigned int locks_length = 0;
424 :
425 0 : ps->is = is;
426 0 : if (NULL != ps->duplicate_of)
427 : {
428 : const struct TALER_TESTING_Command *order_cmd;
429 : const json_t *ct;
430 :
431 0 : order_cmd = TALER_TESTING_interpreter_lookup_command (
432 : is,
433 : ps->duplicate_of);
434 0 : if (GNUNET_OK !=
435 0 : TALER_TESTING_get_trait_order_terms (order_cmd,
436 : &ct))
437 : {
438 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
439 : "Could not fetch previous order string\n");
440 0 : TALER_TESTING_interpreter_fail (is);
441 0 : return;
442 : }
443 0 : order = (json_t *) ct;
444 : }
445 : else
446 : {
447 0 : if (NULL == json_object_get (ps->order_terms,
448 : "order_id"))
449 : {
450 : struct GNUNET_TIME_Absolute now;
451 : char *order_id;
452 :
453 0 : now = GNUNET_TIME_absolute_get_monotonic (is->cfg);
454 0 : order_id = GNUNET_STRINGS_data_to_string_alloc (
455 : &now.abs_value_us,
456 : sizeof (now.abs_value_us));
457 0 : GNUNET_assert (0 ==
458 : json_object_set_new (ps->order_terms,
459 : "order_id",
460 : json_string (order_id)));
461 0 : GNUNET_free (order_id);
462 : }
463 0 : order = ps->order_terms;
464 : }
465 0 : if (NULL == order)
466 : {
467 0 : GNUNET_break (0);
468 0 : TALER_TESTING_interpreter_fail (is);
469 0 : return;
470 : }
471 :
472 0 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
473 0 : &ps->nonce,
474 : sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
475 0 : for (token = strtok (products_string, ";");
476 : NULL != token;
477 0 : token = strtok (NULL, ";"))
478 : {
479 : char *ctok;
480 : struct TALER_MERCHANT_InventoryProduct pd;
481 :
482 : /* Token syntax is "[product_id]/[quantity]" */
483 0 : ctok = strchr (token, '/');
484 0 : if (NULL != ctok)
485 : {
486 0 : *ctok = '\0';
487 0 : ctok++;
488 0 : if (1 != sscanf (ctok,
489 : "%u",
490 : &pd.quantity))
491 : {
492 0 : GNUNET_break (0);
493 0 : break;
494 : }
495 : }
496 : else
497 : {
498 0 : pd.quantity = 1;
499 : }
500 0 : pd.product_id = token;
501 :
502 0 : GNUNET_array_append (products,
503 : products_length,
504 : pd);
505 : }
506 0 : for (token = strtok (locks_string, ";");
507 : NULL != token;
508 0 : token = strtok (NULL, ";"))
509 : {
510 : const struct TALER_TESTING_Command *lock_cmd;
511 : const char **uuid;
512 :
513 0 : lock_cmd = TALER_TESTING_interpreter_lookup_command (
514 : is,
515 : token);
516 :
517 0 : if (GNUNET_OK !=
518 0 : TALER_TESTING_get_trait_lock_uuid (lock_cmd,
519 : &uuid))
520 : {
521 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
522 : "Could not fetch lock uuid\n");
523 0 : TALER_TESTING_interpreter_fail (is);
524 0 : return;
525 : }
526 :
527 0 : GNUNET_array_append (locks,
528 : locks_length,
529 : *uuid);
530 : }
531 0 : ps->po = TALER_MERCHANT_orders_post2 (is->ctx,
532 : ps->merchant_url,
533 : order,
534 0 : GNUNET_TIME_UNIT_ZERO,
535 : ps->payment_target,
536 : products_length,
537 : products,
538 : locks_length,
539 : locks,
540 0 : ps->make_claim_token,
541 : &order_cb,
542 : ps);
543 0 : GNUNET_free (products_string);
544 0 : GNUNET_free (locks_string);
545 0 : GNUNET_array_grow (products,
546 : products_length,
547 : 0);
548 0 : GNUNET_array_grow (locks,
549 : locks_length,
550 : 0);
551 0 : GNUNET_assert (NULL != ps->po);
552 : }
553 :
554 :
555 : /**
556 : * Free the state of a "orders" CMD, and possibly
557 : * cancel it if it did not complete.
558 : *
559 : * @param cls closure.
560 : * @param cmd command being freed.
561 : */
562 : static void
563 0 : orders_cleanup (void *cls,
564 : const struct TALER_TESTING_Command *cmd)
565 : {
566 0 : struct OrdersState *ps = cls;
567 :
568 0 : if (NULL != ps->po)
569 : {
570 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
571 : "Command '%s' did not complete (orders put)\n",
572 : cmd->label);
573 0 : TALER_MERCHANT_orders_post_cancel (ps->po);
574 0 : ps->po = NULL;
575 : }
576 :
577 0 : if (NULL != ps->och)
578 : {
579 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
580 : "Command '%s' did not complete (orders lookup)\n",
581 : cmd->label);
582 0 : TALER_MERCHANT_order_claim_cancel (ps->och);
583 0 : ps->och = NULL;
584 : }
585 :
586 0 : json_decref (ps->contract_terms);
587 0 : json_decref (ps->order_terms);
588 0 : GNUNET_free_nz ((void *) ps->order_id);
589 0 : GNUNET_free (ps);
590 0 : }
591 :
592 :
593 : /**
594 : * Mark part of the contract terms as possible to forget.
595 : *
596 : * @param cls pointer to the result of the forget operation.
597 : * @param object_id name of the object to forget.
598 : * @param parent parent of the object at @e object_id.
599 : */
600 : static void
601 0 : mark_forgettable (void *cls,
602 : const char *object_id,
603 : json_t *parent)
604 : {
605 0 : GNUNET_assert (GNUNET_OK ==
606 : TALER_JSON_contract_mark_forgettable (parent,
607 : object_id));
608 0 : }
609 :
610 :
611 : /**
612 : * Constructs the json for a POST order request.
613 : *
614 : * @param order_id the name of the order to add, can be NULL.
615 : * @param refund_deadline the deadline for refunds on this order.
616 : * @param pay_deadline the deadline for payment on this order.
617 : * @param amount the amount this order is for.
618 : * @param[out] order where to write the json string.
619 : */
620 : static void
621 0 : make_order_json (const char *order_id,
622 : struct GNUNET_TIME_Timestamp refund_deadline,
623 : struct GNUNET_TIME_Timestamp pay_deadline,
624 : const char *amount,
625 : json_t **order)
626 : {
627 0 : struct GNUNET_TIME_Timestamp refund = refund_deadline;
628 0 : struct GNUNET_TIME_Timestamp pay = pay_deadline;
629 : json_t *contract_terms;
630 :
631 : /* Include required fields and some dummy objects to test forgetting. */
632 0 : contract_terms = json_pack (
633 : "{s:s, s:s?, s:s, s:s, s:o, s:o, s:s, s:[{s:s}, {s:s}, {s:s}]}",
634 : "summary", "merchant-lib testcase",
635 : "order_id", order_id,
636 : "amount", amount,
637 : "fulfillment_url", "https://example.com",
638 : "refund_deadline", GNUNET_JSON_from_timestamp (refund),
639 : "pay_deadline", GNUNET_JSON_from_timestamp (pay),
640 : "dummy_obj", "EUR:1.0",
641 : "dummy_array", /* For testing forgetting parts of arrays */
642 : "item", "speakers",
643 : "item", "headphones",
644 : "item", "earbuds"
645 : );
646 0 : GNUNET_assert (GNUNET_OK ==
647 : TALER_JSON_expand_path (contract_terms,
648 : "$.dummy_obj",
649 : &mark_forgettable,
650 : NULL));
651 0 : GNUNET_assert (GNUNET_OK ==
652 : TALER_JSON_expand_path (contract_terms,
653 : "$.dummy_array[*].item",
654 : &mark_forgettable,
655 : NULL));
656 0 : *order = contract_terms;
657 0 : }
658 :
659 :
660 : struct TALER_TESTING_Command
661 0 : TALER_TESTING_cmd_merchant_post_orders_no_claim (
662 : const char *label,
663 : const char *merchant_url,
664 : unsigned int http_status,
665 : const char *order_id,
666 : struct GNUNET_TIME_Timestamp refund_deadline,
667 : struct GNUNET_TIME_Timestamp pay_deadline,
668 : const char *amount)
669 : {
670 : struct OrdersState *ps;
671 :
672 0 : ps = GNUNET_new (struct OrdersState);
673 0 : make_order_json (order_id,
674 : refund_deadline,
675 : pay_deadline,
676 : amount,
677 : &ps->order_terms);
678 0 : ps->http_status = http_status;
679 0 : ps->expected_order_id = order_id;
680 0 : ps->merchant_url = merchant_url;
681 0 : ps->with_claim = false;
682 : {
683 0 : struct TALER_TESTING_Command cmd = {
684 : .cls = ps,
685 : .label = label,
686 : .run = &orders_run,
687 : .cleanup = &orders_cleanup,
688 : .traits = &orders_traits
689 : };
690 :
691 0 : return cmd;
692 : }
693 : }
694 :
695 :
696 : struct TALER_TESTING_Command
697 0 : TALER_TESTING_cmd_merchant_post_orders (
698 : const char *label,
699 : const char *merchant_url,
700 : unsigned int http_status,
701 : const char *order_id,
702 : struct GNUNET_TIME_Timestamp refund_deadline,
703 : struct GNUNET_TIME_Timestamp pay_deadline,
704 : const char *amount)
705 : {
706 : struct OrdersState *ps;
707 :
708 0 : ps = GNUNET_new (struct OrdersState);
709 0 : make_order_json (order_id,
710 : refund_deadline,
711 : pay_deadline,
712 : amount,
713 : &ps->order_terms);
714 0 : ps->http_status = http_status;
715 0 : ps->expected_order_id = order_id;
716 0 : ps->merchant_url = merchant_url;
717 0 : ps->with_claim = true;
718 : {
719 0 : struct TALER_TESTING_Command cmd = {
720 : .cls = ps,
721 : .label = label,
722 : .run = &orders_run,
723 : .cleanup = &orders_cleanup,
724 : .traits = &orders_traits
725 : };
726 :
727 0 : return cmd;
728 : }
729 : }
730 :
731 :
732 : struct TALER_TESTING_Command
733 0 : TALER_TESTING_cmd_merchant_post_orders2 (
734 : const char *label,
735 : const char *merchant_url,
736 : unsigned int http_status,
737 : const char *order_id,
738 : struct GNUNET_TIME_Timestamp refund_deadline,
739 : struct GNUNET_TIME_Timestamp pay_deadline,
740 : bool claim_token,
741 : const char *amount,
742 : const char *payment_target,
743 : const char *products,
744 : const char *locks,
745 : const char *duplicate_of)
746 : {
747 : struct OrdersState *ps;
748 :
749 0 : ps = GNUNET_new (struct OrdersState);
750 0 : make_order_json (order_id,
751 : refund_deadline,
752 : pay_deadline,
753 : amount,
754 : &ps->order_terms);
755 0 : ps->http_status = http_status;
756 0 : ps->expected_order_id = order_id;
757 0 : ps->merchant_url = merchant_url;
758 0 : ps->payment_target = payment_target;
759 0 : ps->products = products;
760 0 : ps->locks = locks;
761 0 : ps->with_claim = (NULL == duplicate_of);
762 0 : ps->make_claim_token = claim_token;
763 0 : ps->duplicate_of = duplicate_of;
764 : {
765 0 : struct TALER_TESTING_Command cmd = {
766 : .cls = ps,
767 : .label = label,
768 : .run = &orders_run2,
769 : .cleanup = &orders_cleanup,
770 : .traits = &orders_traits
771 : };
772 :
773 0 : return cmd;
774 : }
775 : }
|