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 : {
209 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
210 : "Expected status %u, got %u\n",
211 : ps->http_status,
212 : hr->http_status);
213 0 : TALER_TESTING_FAIL (ps->is);
214 : }
215 :
216 0 : ps->contract_terms = json_deep_copy (contract_terms);
217 0 : ps->h_contract_terms = *hash;
218 0 : ps->merchant_sig = *sig;
219 0 : if (GNUNET_OK !=
220 0 : GNUNET_JSON_parse (contract_terms,
221 : spec,
222 : &error_name,
223 : &error_line))
224 : {
225 : char *log;
226 :
227 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
228 : "Parser failed on %s:%u\n",
229 : error_name,
230 : error_line);
231 0 : log = json_dumps (ps->contract_terms,
232 : JSON_INDENT (1));
233 0 : fprintf (stderr,
234 : "%s\n",
235 : log);
236 0 : free (log);
237 0 : TALER_TESTING_FAIL (ps->is);
238 : }
239 0 : ps->merchant_pub = merchant_pub;
240 0 : TALER_TESTING_interpreter_next (ps->is);
241 : }
242 :
243 :
244 : /**
245 : * Callback that processes the response following a
246 : * POST /orders. NOTE: no contract terms are included
247 : * here; they need to be taken via the "orders lookup"
248 : * method.
249 : *
250 : * @param cls closure.
251 : * @param por details about the response
252 : */
253 : static void
254 0 : order_cb (void *cls,
255 : const struct TALER_MERCHANT_PostOrdersReply *por)
256 : {
257 0 : struct OrdersState *ps = cls;
258 :
259 0 : ps->po = NULL;
260 0 : if (ps->http_status != por->hr.http_status)
261 : {
262 0 : TALER_LOG_ERROR ("Given vs expected: %u(%d) vs %u\n",
263 : por->hr.http_status,
264 : (int) por->hr.ec,
265 : ps->http_status);
266 0 : TALER_TESTING_FAIL (ps->is);
267 : }
268 0 : if (0 == ps->http_status)
269 : {
270 0 : TALER_LOG_DEBUG ("/orders, expected 0 status code\n");
271 0 : TALER_TESTING_interpreter_next (ps->is);
272 0 : return;
273 : }
274 0 : switch (por->hr.http_status)
275 : {
276 0 : case MHD_HTTP_OK:
277 0 : if (NULL != por->details.ok.token)
278 0 : ps->claim_token = *por->details.ok.token;
279 0 : ps->order_id = GNUNET_strdup (por->details.ok.order_id);
280 0 : if ((NULL != ps->expected_order_id) &&
281 0 : (0 != strcmp (por->details.ok.order_id,
282 : ps->expected_order_id)))
283 : {
284 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
285 : "Order id assigned does not match\n");
286 0 : TALER_TESTING_interpreter_fail (ps->is);
287 0 : return;
288 : }
289 0 : if (NULL != ps->duplicate_of)
290 : {
291 : const struct TALER_TESTING_Command *order_cmd;
292 : const struct TALER_ClaimTokenP *prev_token;
293 0 : struct TALER_ClaimTokenP zero_token = {0};
294 :
295 0 : order_cmd = TALER_TESTING_interpreter_lookup_command (
296 : ps->is,
297 : ps->duplicate_of);
298 0 : if (GNUNET_OK !=
299 0 : TALER_TESTING_get_trait_claim_token (order_cmd,
300 : &prev_token))
301 : {
302 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
303 : "Could not fetch previous order claim token\n");
304 0 : TALER_TESTING_interpreter_fail (ps->is);
305 0 : return;
306 : }
307 0 : if (NULL == por->details.ok.token)
308 0 : prev_token = &zero_token;
309 0 : if (0 != GNUNET_memcmp (prev_token,
310 : por->details.ok.token))
311 : {
312 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
313 : "Claim tokens for identical requests do not match\n");
314 0 : TALER_TESTING_interpreter_fail (ps->is);
315 0 : return;
316 : }
317 : }
318 0 : break;
319 0 : case MHD_HTTP_NOT_FOUND:
320 0 : TALER_TESTING_interpreter_next (ps->is);
321 0 : return;
322 0 : case MHD_HTTP_GONE:
323 0 : TALER_TESTING_interpreter_next (ps->is);
324 0 : return;
325 0 : case MHD_HTTP_CONFLICT:
326 0 : TALER_TESTING_interpreter_next (ps->is);
327 0 : return;
328 0 : default:
329 : {
330 0 : char *s = json_dumps (por->hr.reply,
331 : JSON_COMPACT);
332 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
333 : "Unexpected status code from /orders: %u (%d) at %s; JSON: %s\n",
334 : por->hr.http_status,
335 : (int) por->hr.ec,
336 : TALER_TESTING_interpreter_get_current_label (ps->is),
337 : s);
338 0 : GNUNET_free (s);
339 : /**
340 : * Not failing, as test cases are _supposed_
341 : * to create non 200 OK situations.
342 : */
343 0 : TALER_TESTING_interpreter_next (ps->is);
344 : }
345 0 : return;
346 : }
347 :
348 0 : if (! ps->with_claim)
349 : {
350 0 : TALER_TESTING_interpreter_next (ps->is);
351 0 : return;
352 : }
353 0 : if (NULL ==
354 0 : (ps->och = TALER_MERCHANT_order_claim (ps->is->ctx,
355 : ps->merchant_url,
356 : ps->order_id,
357 0 : &ps->nonce,
358 0 : &ps->claim_token,
359 : &orders_claim_cb,
360 : ps)))
361 0 : TALER_TESTING_FAIL (ps->is);
362 : }
363 :
364 :
365 : /**
366 : * Run a "orders" CMD.
367 : *
368 : * @param cls closure.
369 : * @param cmd command currently being run.
370 : * @param is interpreter state.
371 : */
372 : static void
373 0 : orders_run (void *cls,
374 : const struct TALER_TESTING_Command *cmd,
375 : struct TALER_TESTING_Interpreter *is)
376 : {
377 0 : struct OrdersState *ps = cls;
378 :
379 0 : ps->is = is;
380 0 : if (NULL == json_object_get (ps->order_terms,
381 : "order_id"))
382 : {
383 : struct GNUNET_TIME_Absolute now;
384 : char *order_id;
385 :
386 0 : now = GNUNET_TIME_absolute_get_monotonic (is->cfg);
387 0 : order_id = GNUNET_STRINGS_data_to_string_alloc (
388 : &now,
389 : sizeof (now));
390 0 : GNUNET_assert (0 ==
391 : json_object_set_new (ps->order_terms,
392 : "order_id",
393 : json_string (order_id)));
394 0 : GNUNET_free (order_id);
395 : }
396 0 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
397 0 : &ps->nonce,
398 : sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
399 0 : ps->po = TALER_MERCHANT_orders_post (is->ctx,
400 : ps->merchant_url,
401 0 : ps->order_terms,
402 0 : GNUNET_TIME_UNIT_ZERO,
403 : &order_cb,
404 : ps);
405 0 : GNUNET_assert (NULL != ps->po);
406 0 : }
407 :
408 :
409 : /**
410 : * Run a "orders" CMD.
411 : *
412 : * @param cls closure.
413 : * @param cmd command currently being run.
414 : * @param is interpreter state.
415 : */
416 : static void
417 0 : orders_run2 (void *cls,
418 : const struct TALER_TESTING_Command *cmd,
419 : struct TALER_TESTING_Interpreter *is)
420 : {
421 0 : struct OrdersState *ps = cls;
422 : const json_t *order;
423 0 : char *products_string = GNUNET_strdup (ps->products);
424 0 : char *locks_string = GNUNET_strdup (ps->locks);
425 : char *token;
426 0 : struct TALER_MERCHANT_InventoryProduct *products = NULL;
427 0 : unsigned int products_length = 0;
428 0 : const char **locks = NULL;
429 0 : unsigned int locks_length = 0;
430 :
431 0 : ps->is = is;
432 0 : if (NULL != ps->duplicate_of)
433 : {
434 : const struct TALER_TESTING_Command *order_cmd;
435 : const json_t *ct;
436 :
437 0 : order_cmd = TALER_TESTING_interpreter_lookup_command (
438 : is,
439 : ps->duplicate_of);
440 0 : if (GNUNET_OK !=
441 0 : TALER_TESTING_get_trait_order_terms (order_cmd,
442 : &ct))
443 : {
444 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
445 : "Could not fetch previous order string\n");
446 0 : TALER_TESTING_interpreter_fail (is);
447 0 : return;
448 : }
449 0 : order = (json_t *) ct;
450 : }
451 : else
452 : {
453 0 : if (NULL == json_object_get (ps->order_terms,
454 : "order_id"))
455 : {
456 : struct GNUNET_TIME_Absolute now;
457 : char *order_id;
458 :
459 0 : now = GNUNET_TIME_absolute_get_monotonic (is->cfg);
460 0 : order_id = GNUNET_STRINGS_data_to_string_alloc (
461 : &now.abs_value_us,
462 : sizeof (now.abs_value_us));
463 0 : GNUNET_assert (0 ==
464 : json_object_set_new (ps->order_terms,
465 : "order_id",
466 : json_string (order_id)));
467 0 : GNUNET_free (order_id);
468 : }
469 0 : order = ps->order_terms;
470 : }
471 0 : if (NULL == order)
472 : {
473 0 : GNUNET_break (0);
474 0 : TALER_TESTING_interpreter_fail (is);
475 0 : return;
476 : }
477 :
478 0 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
479 0 : &ps->nonce,
480 : sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
481 0 : for (token = strtok (products_string, ";");
482 : NULL != token;
483 0 : token = strtok (NULL, ";"))
484 : {
485 : char *ctok;
486 : struct TALER_MERCHANT_InventoryProduct pd;
487 :
488 : /* Token syntax is "[product_id]/[quantity]" */
489 0 : ctok = strchr (token, '/');
490 0 : if (NULL != ctok)
491 : {
492 0 : *ctok = '\0';
493 0 : ctok++;
494 0 : if (1 != sscanf (ctok,
495 : "%u",
496 : &pd.quantity))
497 : {
498 0 : GNUNET_break (0);
499 0 : break;
500 : }
501 : }
502 : else
503 : {
504 0 : pd.quantity = 1;
505 : }
506 0 : pd.product_id = token;
507 :
508 0 : GNUNET_array_append (products,
509 : products_length,
510 : pd);
511 : }
512 0 : for (token = strtok (locks_string, ";");
513 : NULL != token;
514 0 : token = strtok (NULL, ";"))
515 : {
516 : const struct TALER_TESTING_Command *lock_cmd;
517 : const char **uuid;
518 :
519 0 : lock_cmd = TALER_TESTING_interpreter_lookup_command (
520 : is,
521 : token);
522 :
523 0 : if (GNUNET_OK !=
524 0 : TALER_TESTING_get_trait_lock_uuid (lock_cmd,
525 : &uuid))
526 : {
527 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
528 : "Could not fetch lock uuid\n");
529 0 : TALER_TESTING_interpreter_fail (is);
530 0 : return;
531 : }
532 :
533 0 : GNUNET_array_append (locks,
534 : locks_length,
535 : *uuid);
536 : }
537 0 : ps->po = TALER_MERCHANT_orders_post2 (is->ctx,
538 : ps->merchant_url,
539 : order,
540 0 : GNUNET_TIME_UNIT_ZERO,
541 : ps->payment_target,
542 : products_length,
543 : products,
544 : locks_length,
545 : locks,
546 0 : ps->make_claim_token,
547 : &order_cb,
548 : ps);
549 0 : GNUNET_free (products_string);
550 0 : GNUNET_free (locks_string);
551 0 : GNUNET_array_grow (products,
552 : products_length,
553 : 0);
554 0 : GNUNET_array_grow (locks,
555 : locks_length,
556 : 0);
557 0 : GNUNET_assert (NULL != ps->po);
558 : }
559 :
560 :
561 : /**
562 : * Free the state of a "orders" CMD, and possibly
563 : * cancel it if it did not complete.
564 : *
565 : * @param cls closure.
566 : * @param cmd command being freed.
567 : */
568 : static void
569 0 : orders_cleanup (void *cls,
570 : const struct TALER_TESTING_Command *cmd)
571 : {
572 0 : struct OrdersState *ps = cls;
573 :
574 0 : if (NULL != ps->po)
575 : {
576 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
577 : "Command '%s' did not complete (orders put)\n",
578 : cmd->label);
579 0 : TALER_MERCHANT_orders_post_cancel (ps->po);
580 0 : ps->po = NULL;
581 : }
582 :
583 0 : if (NULL != ps->och)
584 : {
585 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
586 : "Command '%s' did not complete (orders lookup)\n",
587 : cmd->label);
588 0 : TALER_MERCHANT_order_claim_cancel (ps->och);
589 0 : ps->och = NULL;
590 : }
591 :
592 0 : json_decref (ps->contract_terms);
593 0 : json_decref (ps->order_terms);
594 0 : GNUNET_free_nz ((void *) ps->order_id);
595 0 : GNUNET_free (ps);
596 0 : }
597 :
598 :
599 : /**
600 : * Mark part of the contract terms as possible to forget.
601 : *
602 : * @param cls pointer to the result of the forget operation.
603 : * @param object_id name of the object to forget.
604 : * @param parent parent of the object at @e object_id.
605 : */
606 : static void
607 0 : mark_forgettable (void *cls,
608 : const char *object_id,
609 : json_t *parent)
610 : {
611 0 : GNUNET_assert (GNUNET_OK ==
612 : TALER_JSON_contract_mark_forgettable (parent,
613 : object_id));
614 0 : }
615 :
616 :
617 : /**
618 : * Constructs the json for a POST order request.
619 : *
620 : * @param order_id the name of the order to add, can be NULL.
621 : * @param refund_deadline the deadline for refunds on this order.
622 : * @param pay_deadline the deadline for payment on this order.
623 : * @param amount the amount this order is for.
624 : * @param[out] order where to write the json string.
625 : */
626 : static void
627 0 : make_order_json (const char *order_id,
628 : struct GNUNET_TIME_Timestamp refund_deadline,
629 : struct GNUNET_TIME_Timestamp pay_deadline,
630 : const char *amount,
631 : json_t **order)
632 : {
633 0 : struct GNUNET_TIME_Timestamp refund = refund_deadline;
634 0 : struct GNUNET_TIME_Timestamp pay = pay_deadline;
635 : json_t *contract_terms;
636 :
637 : /* Include required fields and some dummy objects to test forgetting. */
638 0 : contract_terms = json_pack (
639 : "{s:s, s:s?, s:s, s:s, s:o, s:o, s:s, s:[{s:s}, {s:s}, {s:s}]}",
640 : "summary", "merchant-lib testcase",
641 : "order_id", order_id,
642 : "amount", amount,
643 : "fulfillment_url", "https://example.com",
644 : "refund_deadline", GNUNET_JSON_from_timestamp (refund),
645 : "pay_deadline", GNUNET_JSON_from_timestamp (pay),
646 : "dummy_obj", "EUR:1.0",
647 : "dummy_array", /* For testing forgetting parts of arrays */
648 : "item", "speakers",
649 : "item", "headphones",
650 : "item", "earbuds"
651 : );
652 0 : GNUNET_assert (GNUNET_OK ==
653 : TALER_JSON_expand_path (contract_terms,
654 : "$.dummy_obj",
655 : &mark_forgettable,
656 : NULL));
657 0 : GNUNET_assert (GNUNET_OK ==
658 : TALER_JSON_expand_path (contract_terms,
659 : "$.dummy_array[*].item",
660 : &mark_forgettable,
661 : NULL));
662 0 : *order = contract_terms;
663 0 : }
664 :
665 :
666 : struct TALER_TESTING_Command
667 0 : TALER_TESTING_cmd_merchant_post_orders_no_claim (
668 : const char *label,
669 : const char *merchant_url,
670 : unsigned int http_status,
671 : const char *order_id,
672 : struct GNUNET_TIME_Timestamp refund_deadline,
673 : struct GNUNET_TIME_Timestamp pay_deadline,
674 : const char *amount)
675 : {
676 : struct OrdersState *ps;
677 :
678 0 : ps = GNUNET_new (struct OrdersState);
679 0 : make_order_json (order_id,
680 : refund_deadline,
681 : pay_deadline,
682 : amount,
683 : &ps->order_terms);
684 0 : ps->http_status = http_status;
685 0 : ps->expected_order_id = order_id;
686 0 : ps->merchant_url = merchant_url;
687 0 : ps->with_claim = false;
688 : {
689 0 : struct TALER_TESTING_Command cmd = {
690 : .cls = ps,
691 : .label = label,
692 : .run = &orders_run,
693 : .cleanup = &orders_cleanup,
694 : .traits = &orders_traits
695 : };
696 :
697 0 : return cmd;
698 : }
699 : }
700 :
701 :
702 : struct TALER_TESTING_Command
703 0 : TALER_TESTING_cmd_merchant_post_orders (
704 : const char *label,
705 : const char *merchant_url,
706 : unsigned int http_status,
707 : const char *order_id,
708 : struct GNUNET_TIME_Timestamp refund_deadline,
709 : struct GNUNET_TIME_Timestamp pay_deadline,
710 : const char *amount)
711 : {
712 : struct OrdersState *ps;
713 :
714 0 : ps = GNUNET_new (struct OrdersState);
715 0 : make_order_json (order_id,
716 : refund_deadline,
717 : pay_deadline,
718 : amount,
719 : &ps->order_terms);
720 0 : ps->http_status = http_status;
721 0 : ps->expected_order_id = order_id;
722 0 : ps->merchant_url = merchant_url;
723 0 : ps->with_claim = true;
724 : {
725 0 : struct TALER_TESTING_Command cmd = {
726 : .cls = ps,
727 : .label = label,
728 : .run = &orders_run,
729 : .cleanup = &orders_cleanup,
730 : .traits = &orders_traits
731 : };
732 :
733 0 : return cmd;
734 : }
735 : }
736 :
737 :
738 : struct TALER_TESTING_Command
739 0 : TALER_TESTING_cmd_merchant_post_orders2 (
740 : const char *label,
741 : const char *merchant_url,
742 : unsigned int http_status,
743 : const char *order_id,
744 : struct GNUNET_TIME_Timestamp refund_deadline,
745 : struct GNUNET_TIME_Timestamp pay_deadline,
746 : bool claim_token,
747 : const char *amount,
748 : const char *payment_target,
749 : const char *products,
750 : const char *locks,
751 : const char *duplicate_of)
752 : {
753 : struct OrdersState *ps;
754 :
755 0 : ps = GNUNET_new (struct OrdersState);
756 0 : make_order_json (order_id,
757 : refund_deadline,
758 : pay_deadline,
759 : amount,
760 : &ps->order_terms);
761 0 : ps->http_status = http_status;
762 0 : ps->expected_order_id = order_id;
763 0 : ps->merchant_url = merchant_url;
764 0 : ps->payment_target = payment_target;
765 0 : ps->products = products;
766 0 : ps->locks = locks;
767 0 : ps->with_claim = (NULL == duplicate_of);
768 0 : ps->make_claim_token = claim_token;
769 0 : ps->duplicate_of = duplicate_of;
770 : {
771 0 : struct TALER_TESTING_Command cmd = {
772 : .cls = ps,
773 : .label = label,
774 : .run = &orders_run2,
775 : .cleanup = &orders_cleanup,
776 : .traits = &orders_traits
777 : };
778 :
779 0 : return cmd;
780 : }
781 : }
|