Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2020 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 : * @file src/testing/testing_api_cmd_wallet_get_order.c
21 : * @brief command to test GET /order/$ORDER_ID
22 : * @author Jonathan Buchanan
23 : */
24 : #include "platform.h"
25 : #include <taler/taler_exchange_service.h>
26 : #include <taler/taler_testing_lib.h>
27 : #include "taler/taler_merchant_service.h"
28 : #include "taler/taler_merchant_testing_lib.h"
29 : #include <taler/merchant/get-orders-ORDER_ID.h>
30 :
31 :
32 : /**
33 : * State for a GET /orders/$ORDER_ID CMD.
34 : */
35 : struct WalletGetOrderState
36 : {
37 : /**
38 : * The merchant base URL.
39 : */
40 : const char *merchant_url;
41 :
42 : /**
43 : * Expected HTTP response code for this CMD.
44 : */
45 : unsigned int http_status;
46 :
47 : /**
48 : * The handle to the current GET /orders/$ORDER_ID request.
49 : */
50 : struct TALER_MERCHANT_GetOrdersHandle *ogh;
51 :
52 : /**
53 : * The interpreter state.
54 : */
55 : struct TALER_TESTING_Interpreter *is;
56 :
57 : /**
58 : * Reference to a command that created an order.
59 : */
60 : const char *order_reference;
61 :
62 : /**
63 : * Reference to a command that created a paid
64 : * equivalent order that we expect to be referred
65 : * to during repurchase detection, or NULL.
66 : */
67 : const char *repurchase_order_ref;
68 :
69 : /**
70 : * Session Id the order needs to be bound to.
71 : */
72 : const char *session_id;
73 :
74 : /**
75 : * Whether the order was paid or not.
76 : */
77 : bool paid;
78 :
79 : /**
80 : * Whether the order was refunded or not.
81 : */
82 : bool refunded;
83 :
84 : /**
85 : * Whether the order has refunds pending.
86 : */
87 : bool refund_pending;
88 : };
89 :
90 :
91 : /**
92 : * Callback to process a GET /orders/$ID request
93 : *
94 : * @param cls closure
95 : * @param owgr response details
96 : */
97 : /* FIXME_POLYMORPHISM: TALER_MERCHANT_GetOrdersCallback is used in this compilation
98 : unit with two different closure types (struct WalletGetOrderState here, struct
99 : WalletPollOrderStartState in wallet_poll_order_cb below), so a single
100 : TALER_MERCHANT_GET_ORDERS_RESULT_CLOSURE override cannot type both. Left as void *cls;
101 : adopting the RESULT_CLOSURE pattern needs a manual refactor. */
102 : static void
103 21 : wallet_get_order_cb (
104 : void *cls,
105 : const struct TALER_MERCHANT_GetOrdersResponse *owgr)
106 : {
107 21 : struct WalletGetOrderState *gos = cls;
108 21 : const struct TALER_MERCHANT_HttpResponse *hr = &owgr->hr;
109 :
110 21 : gos->ogh = NULL;
111 21 : if (gos->http_status != hr->http_status)
112 : {
113 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
114 : "Unexpected response code %u (%d) to command %s\n",
115 : hr->http_status,
116 : (int) hr->ec,
117 : TALER_TESTING_interpreter_get_current_label (gos->is));
118 0 : TALER_TESTING_interpreter_fail (gos->is);
119 0 : return;
120 : }
121 21 : switch (hr->http_status)
122 : {
123 14 : case MHD_HTTP_OK:
124 14 : if (gos->refunded != owgr->details.ok.refunded)
125 : {
126 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
127 : "Order refunded does not match\n");
128 0 : TALER_TESTING_interpreter_fail (gos->is);
129 0 : return;
130 : }
131 14 : if (gos->refund_pending != owgr->details.ok.refund_pending)
132 : {
133 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
134 : "Order refund pending does not match\n");
135 0 : TALER_TESTING_interpreter_fail (gos->is);
136 0 : return;
137 : }
138 14 : break;
139 7 : case MHD_HTTP_PAYMENT_REQUIRED:
140 : {
141 : struct TALER_MERCHANT_PayUriData pud;
142 : const struct TALER_TESTING_Command *order_cmd;
143 : const char *order_id;
144 : const struct TALER_ClaimTokenP *claim_token;
145 :
146 7 : if (NULL != gos->repurchase_order_ref)
147 : {
148 : const struct TALER_TESTING_Command *rep_cmd;
149 : const char *rep_id;
150 : const char *ri;
151 :
152 2 : rep_cmd = TALER_TESTING_interpreter_lookup_command (
153 : gos->is,
154 : gos->repurchase_order_ref);
155 2 : if (GNUNET_OK !=
156 2 : TALER_TESTING_get_trait_order_id (rep_cmd,
157 : &rep_id))
158 : {
159 0 : TALER_TESTING_FAIL (gos->is);
160 : }
161 2 : ri = owgr->details.payment_required.already_paid_order_id;
162 2 : if ( (NULL == ri) ||
163 : (0 !=
164 2 : strcmp (ri,
165 : rep_id)) )
166 : {
167 0 : TALER_TESTING_FAIL (gos->is);
168 : }
169 : }
170 :
171 7 : if (GNUNET_OK !=
172 7 : TALER_MERCHANT_parse_pay_uri (
173 7 : owgr->details.payment_required.taler_pay_uri,
174 : &pud))
175 : {
176 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
177 : "Taler pay uri `%s' is malformed\n",
178 : owgr->details.payment_required.taler_pay_uri);
179 0 : TALER_TESTING_interpreter_fail (gos->is);
180 0 : return;
181 : }
182 :
183 7 : order_cmd = TALER_TESTING_interpreter_lookup_command (
184 : gos->is,
185 : gos->order_reference);
186 :
187 7 : if (GNUNET_OK !=
188 7 : TALER_TESTING_get_trait_order_id (order_cmd,
189 : &order_id))
190 : {
191 0 : TALER_MERCHANT_parse_pay_uri_free (&pud);
192 0 : TALER_TESTING_FAIL (gos->is);
193 : }
194 :
195 7 : if (GNUNET_OK !=
196 7 : TALER_TESTING_get_trait_claim_token (order_cmd,
197 : &claim_token))
198 : {
199 0 : TALER_MERCHANT_parse_pay_uri_free (&pud);
200 0 : TALER_TESTING_FAIL (gos->is);
201 : }
202 :
203 : {
204 : char *host;
205 :
206 7 : host = TALER_MERCHANT_TESTING_extract_host (gos->merchant_url);
207 7 : if ((0 != strcmp (host,
208 7 : pud.merchant_host)) ||
209 7 : (NULL != pud.merchant_prefix_path) ||
210 7 : (0 != strcmp (order_id,
211 7 : pud.order_id)) ||
212 7 : (NULL != pud.ssid))
213 : {
214 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
215 : "Order pay uri `%s' does not match `%s'\n",
216 : owgr->details.payment_required.taler_pay_uri,
217 : pud.order_id);
218 0 : TALER_TESTING_interpreter_fail (gos->is);
219 0 : TALER_MERCHANT_parse_pay_uri_free (&pud);
220 0 : GNUNET_free (host);
221 0 : return;
222 : }
223 7 : GNUNET_free (host);
224 : }
225 : /* The claim token is not given in the pay uri if the order
226 : has been claimed already. */
227 7 : if ((NULL != pud.claim_token) &&
228 0 : ((NULL == claim_token) ||
229 0 : (0 != GNUNET_memcmp (claim_token,
230 : pud.claim_token))))
231 : {
232 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
233 : "Order pay uri claim token does not match (%d/%d)\n",
234 : NULL == pud.claim_token,
235 : NULL == claim_token);
236 0 : TALER_TESTING_interpreter_fail (gos->is);
237 0 : TALER_MERCHANT_parse_pay_uri_free (&pud);
238 0 : return;
239 : }
240 7 : TALER_MERCHANT_parse_pay_uri_free (&pud);
241 : }
242 7 : break;
243 0 : default:
244 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
245 : "Unhandled HTTP status.\n");
246 : }
247 21 : TALER_TESTING_interpreter_next (gos->is);
248 : }
249 :
250 :
251 : /**
252 : * Run the "GET order" CMD.
253 : *
254 : * @param cls closure.
255 : * @param cmd command being run now.
256 : * @param is interpreter state.
257 : */
258 : static void
259 21 : wallet_get_order_run (void *cls,
260 : const struct TALER_TESTING_Command *cmd,
261 : struct TALER_TESTING_Interpreter *is)
262 : {
263 21 : struct WalletGetOrderState *gos = cls;
264 : const struct TALER_TESTING_Command *order_cmd;
265 : const char *order_id;
266 : const struct TALER_PrivateContractHashP *h_contract;
267 :
268 21 : order_cmd = TALER_TESTING_interpreter_lookup_command (
269 : is,
270 : gos->order_reference);
271 :
272 21 : if (GNUNET_OK !=
273 21 : TALER_TESTING_get_trait_order_id (order_cmd,
274 : &order_id))
275 0 : TALER_TESTING_FAIL (is);
276 :
277 21 : if (GNUNET_OK !=
278 21 : TALER_TESTING_get_trait_h_contract_terms (order_cmd,
279 : &h_contract))
280 0 : TALER_TESTING_FAIL (is);
281 :
282 21 : gos->is = is;
283 21 : gos->ogh = TALER_MERCHANT_get_orders_create (
284 : TALER_TESTING_interpreter_get_context (is),
285 : gos->merchant_url,
286 : order_id);
287 21 : GNUNET_assert (
288 : GNUNET_OK ==
289 : TALER_MERCHANT_get_orders_set_options (
290 : gos->ogh,
291 : TALER_MERCHANT_get_orders_option_h_contract (*h_contract),
292 : TALER_MERCHANT_get_orders_option_session_id (gos->session_id)));
293 : {
294 : enum TALER_ErrorCode ec;
295 :
296 21 : ec = TALER_MERCHANT_get_orders_start (
297 : gos->ogh,
298 : &wallet_get_order_cb,
299 : gos);
300 21 : GNUNET_assert (TALER_EC_NONE == ec);
301 : }
302 : }
303 :
304 :
305 : /**
306 : * Free the state of a "GET order" CMD, and possibly
307 : * cancel a pending operation thereof.
308 : *
309 : * @param cls closure.
310 : * @param cmd command being run.
311 : */
312 : static void
313 21 : wallet_get_order_cleanup (void *cls,
314 : const struct TALER_TESTING_Command *cmd)
315 : {
316 21 : struct WalletGetOrderState *gos = cls;
317 :
318 21 : if (NULL != gos->ogh)
319 : {
320 0 : TALER_LOG_WARNING ("Get order operation did not complete\n");
321 0 : TALER_MERCHANT_get_orders_cancel (gos->ogh);
322 : }
323 21 : GNUNET_free (gos);
324 21 : }
325 :
326 :
327 : struct TALER_TESTING_Command
328 13 : TALER_TESTING_cmd_wallet_get_order (
329 : const char *label,
330 : const char *merchant_url,
331 : const char *order_reference,
332 : bool paid,
333 : bool refunded,
334 : bool refund_pending,
335 : unsigned int http_status)
336 : {
337 : struct WalletGetOrderState *gos;
338 :
339 13 : gos = GNUNET_new (struct WalletGetOrderState);
340 13 : gos->merchant_url = merchant_url;
341 13 : gos->order_reference = order_reference;
342 13 : gos->http_status = http_status;
343 13 : gos->paid = paid;
344 13 : gos->refunded = refunded;
345 13 : gos->refund_pending = refund_pending;
346 : {
347 13 : struct TALER_TESTING_Command cmd = {
348 : .cls = gos,
349 : .label = label,
350 : .run = &wallet_get_order_run,
351 : .cleanup = &wallet_get_order_cleanup
352 : };
353 :
354 13 : return cmd;
355 : }
356 : }
357 :
358 :
359 : struct TALER_TESTING_Command
360 8 : TALER_TESTING_cmd_wallet_get_order2 (
361 : const char *label,
362 : const char *merchant_url,
363 : const char *order_reference,
364 : const char *session_id,
365 : bool paid,
366 : bool refunded,
367 : bool refund_pending,
368 : const char *repurchase_order_ref,
369 : unsigned int http_status)
370 : {
371 : struct WalletGetOrderState *gos;
372 :
373 8 : gos = GNUNET_new (struct WalletGetOrderState);
374 8 : gos->merchant_url = merchant_url;
375 8 : gos->order_reference = order_reference;
376 8 : gos->http_status = http_status;
377 8 : gos->paid = paid;
378 8 : gos->session_id = session_id;
379 8 : gos->refunded = refunded;
380 8 : gos->refund_pending = refund_pending;
381 8 : gos->repurchase_order_ref = repurchase_order_ref;
382 : {
383 8 : struct TALER_TESTING_Command cmd = {
384 : .cls = gos,
385 : .label = label,
386 : .run = &wallet_get_order_run,
387 : .cleanup = &wallet_get_order_cleanup
388 : };
389 :
390 8 : return cmd;
391 : }
392 : }
393 :
394 :
395 : struct WalletPollOrderConcludeState
396 : {
397 : /**
398 : * The interpreter state.
399 : */
400 : struct TALER_TESTING_Interpreter *is;
401 :
402 : /**
403 : * Reference to a command that can provide a poll order start command.
404 : */
405 : const char *start_reference;
406 :
407 : /**
408 : * Already paid order ID expected, or NULL for none.
409 : */
410 : const char *already_paid_order_id;
411 :
412 : /**
413 : * Task to wait for the deadline.
414 : */
415 : struct GNUNET_SCHEDULER_Task *task;
416 :
417 : /**
418 : * Amount of a refund expected.
419 : */
420 : struct TALER_Amount expected_refund_amount;
421 :
422 : /**
423 : * Expected HTTP response status code.
424 : */
425 : unsigned int expected_http_status;
426 :
427 : /**
428 : * Are we expecting a refund?
429 : */
430 : bool expected_refund;
431 : };
432 :
433 :
434 : struct WalletPollOrderStartState
435 : {
436 : /**
437 : * The merchant base URL.
438 : */
439 : const char *merchant_url;
440 :
441 : /**
442 : * The handle to the current GET /orders/$ORDER_ID request.
443 : */
444 : struct TALER_MERCHANT_GetOrdersHandle *ogh;
445 :
446 : /**
447 : * The interpreter state.
448 : */
449 : struct TALER_TESTING_Interpreter *is;
450 :
451 : /**
452 : * Reference to a command that created an order.
453 : */
454 : const char *order_ref;
455 :
456 : /**
457 : * Which session ID to poll for.
458 : */
459 : const char *session_id;
460 :
461 : /**
462 : * How long to wait for server to return a response.
463 : */
464 : struct GNUNET_TIME_Relative timeout;
465 :
466 : /**
467 : * Conclude state waiting for completion (if any).
468 : */
469 : struct WalletPollOrderConcludeState *cs;
470 :
471 : /**
472 : * The HTTP status code returned by the backend.
473 : */
474 : unsigned int http_status;
475 :
476 : /**
477 : * When the request should be completed by.
478 : */
479 : struct GNUNET_TIME_Absolute deadline;
480 :
481 : /**
482 : * Minimum refund to wait for.
483 : */
484 : struct TALER_Amount refund_threshold;
485 :
486 : /**
487 : * Available refund as returned by the merchant.
488 : */
489 : struct TALER_Amount refund_available;
490 :
491 : /**
492 : * Already paid order ID returned, or NULL for none.
493 : */
494 : char *already_paid_order_id;
495 :
496 : /**
497 : * Should we poll for a refund?
498 : */
499 : bool wait_for_refund;
500 :
501 : /**
502 : * Did we receive a refund according to response from the merchant?
503 : */
504 : bool refunded;
505 :
506 : /**
507 : * Was the order paid according to response from the merchant?
508 : */
509 : bool paid;
510 :
511 : /**
512 : * Has the order a pending refund according to response from the merchant?
513 : */
514 : bool refund_pending;
515 : };
516 :
517 :
518 : /**
519 : * Task called when either the timeout for the GET /private/order/$ID command
520 : * expired or we got a response. Checks if the result is what we expected.
521 : *
522 : * @param cls a `struct WalletPollOrderConcludeState`
523 : */
524 : static void
525 8 : conclude_task (void *cls)
526 : {
527 8 : struct WalletPollOrderConcludeState *ppc = cls;
528 : const struct TALER_TESTING_Command *poll_cmd;
529 : struct WalletPollOrderStartState *cps;
530 : struct GNUNET_TIME_Absolute now;
531 :
532 8 : ppc->task = NULL;
533 : poll_cmd =
534 8 : TALER_TESTING_interpreter_lookup_command (ppc->is,
535 : ppc->start_reference);
536 8 : if (NULL == poll_cmd)
537 0 : TALER_TESTING_FAIL (ppc->is);
538 8 : cps = poll_cmd->cls;
539 8 : if (NULL != cps->ogh)
540 : {
541 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
542 : "Expected poll GET /orders/$ORDER_ID to have completed, but it did not!\n");
543 0 : TALER_TESTING_FAIL (ppc->is);
544 : }
545 8 : if (cps->http_status != ppc->expected_http_status)
546 : {
547 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
548 : "Expected HTTP status %u, got %u\n",
549 : ppc->expected_http_status,
550 : cps->http_status);
551 0 : TALER_TESTING_FAIL (ppc->is);
552 : }
553 8 : if (ppc->expected_refund != cps->refunded)
554 : {
555 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
556 : "Order was %srefunded, contrary to our expectations\n",
557 : cps->refunded ? "" : "NOT ");
558 0 : TALER_TESTING_FAIL (ppc->is);
559 : }
560 8 : if ( (NULL == ppc->already_paid_order_id)
561 8 : ^ (NULL == cps->already_paid_order_id) )
562 : {
563 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
564 : "Mismatch in already paid order IDs: %s vs %s\n",
565 : ppc->already_paid_order_id,
566 : cps->already_paid_order_id);
567 0 : TALER_TESTING_FAIL (ppc->is);
568 : }
569 8 : if ( (NULL != ppc->already_paid_order_id) &&
570 2 : (0 != strcmp (ppc->already_paid_order_id,
571 2 : cps->already_paid_order_id) ) )
572 : {
573 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
574 : "Mismatch in already paid order IDs: %s vs %s\n",
575 : ppc->already_paid_order_id,
576 : cps->already_paid_order_id);
577 0 : TALER_TESTING_FAIL (ppc->is);
578 : }
579 :
580 8 : if (cps->refunded)
581 : {
582 4 : if (0 != TALER_amount_cmp (&ppc->expected_refund_amount,
583 4 : &cps->refund_available))
584 : {
585 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
586 : "Refund amount %s does not match our expectation!\n",
587 : TALER_amount2s (&cps->refund_available));
588 0 : TALER_TESTING_FAIL (ppc->is);
589 : }
590 : }
591 : // FIXME: add checks for cps->paid/refund_available status flags?
592 8 : now = GNUNET_TIME_absolute_get ();
593 8 : if ((GNUNET_TIME_absolute_add (cps->deadline,
594 8 : GNUNET_TIME_UNIT_SECONDS).abs_value_us <
595 8 : now.abs_value_us) )
596 : {
597 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
598 : "Expected answer to be delayed until %llu, but got response at %llu\n",
599 : (unsigned long long) cps->deadline.abs_value_us,
600 : (unsigned long long) now.abs_value_us);
601 0 : TALER_TESTING_FAIL (ppc->is);
602 : }
603 8 : TALER_TESTING_interpreter_next (ppc->is);
604 : }
605 :
606 :
607 : /**
608 : * Process response from a GET /orders/$ID request
609 : *
610 : * @param cls a `struct WalletPollOrderStartState *`
611 : * @param owgr response details
612 : */
613 : /* FIXME_POLYMORPHISM: see wallet_get_order_cb above — same GetOrdersCallback typedef is
614 : reused here with a different closure type, so this compilation unit cannot adopt a
615 : single TALER_MERCHANT_GET_ORDERS_RESULT_CLOSURE override. Left as void *cls. */
616 : static void
617 8 : wallet_poll_order_cb (
618 : void *cls,
619 : const struct TALER_MERCHANT_GetOrdersResponse *owgr)
620 : {
621 8 : struct WalletPollOrderStartState *pos = cls;
622 8 : const struct TALER_MERCHANT_HttpResponse *hr = &owgr->hr;
623 :
624 8 : pos->ogh = NULL;
625 8 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
626 : "GET /orders/$ID finished with status %u.\n",
627 : hr->http_status);
628 8 : pos->http_status = hr->http_status;
629 8 : switch (hr->http_status)
630 : {
631 6 : case MHD_HTTP_OK:
632 6 : pos->paid = true;
633 6 : pos->refunded = owgr->details.ok.refunded;
634 6 : pos->refund_pending = owgr->details.ok.refund_pending;
635 6 : if (owgr->details.ok.refunded)
636 4 : pos->refund_available = owgr->details.ok.refund_amount;
637 6 : break;
638 2 : case MHD_HTTP_PAYMENT_REQUIRED:
639 2 : if (NULL != owgr->details.payment_required.already_paid_order_id)
640 2 : pos->already_paid_order_id = GNUNET_strdup (
641 : owgr->details.payment_required.already_paid_order_id);
642 2 : break;
643 0 : default:
644 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
645 : "Unhandled HTTP status.\n");
646 0 : break;
647 : }
648 8 : if ( (NULL != pos->cs) &&
649 4 : (NULL != pos->cs->task) )
650 : {
651 4 : GNUNET_SCHEDULER_cancel (pos->cs->task);
652 4 : pos->cs->task = GNUNET_SCHEDULER_add_now (&conclude_task,
653 4 : pos->cs);
654 : }
655 8 : }
656 :
657 :
658 : /**
659 : * Run the "GET order" CMD.
660 : *
661 : * @param cls closure.
662 : * @param cmd command being run now.
663 : * @param is interpreter state.
664 : */
665 : static void
666 8 : wallet_poll_order_start_run (void *cls,
667 : const struct TALER_TESTING_Command *cmd,
668 : struct TALER_TESTING_Interpreter *is)
669 : {
670 8 : struct WalletPollOrderStartState *pos = cls;
671 : const struct TALER_TESTING_Command *order_cmd;
672 : const char *order_id;
673 : const struct TALER_PrivateContractHashP *h_contract;
674 :
675 8 : order_cmd = TALER_TESTING_interpreter_lookup_command (
676 : is,
677 : pos->order_ref);
678 :
679 8 : if (GNUNET_OK !=
680 8 : TALER_TESTING_get_trait_order_id (order_cmd,
681 : &order_id))
682 0 : TALER_TESTING_FAIL (is);
683 :
684 8 : if (GNUNET_OK !=
685 8 : TALER_TESTING_get_trait_h_contract_terms (order_cmd,
686 : &h_contract))
687 0 : TALER_TESTING_FAIL (is);
688 :
689 : /* add 1s grace time to timeout */
690 : pos->deadline
691 8 : = GNUNET_TIME_absolute_add (GNUNET_TIME_relative_to_absolute (pos->timeout),
692 : GNUNET_TIME_UNIT_SECONDS);
693 8 : pos->is = is;
694 8 : pos->ogh = TALER_MERCHANT_get_orders_create (
695 : TALER_TESTING_interpreter_get_context (is),
696 : pos->merchant_url,
697 : order_id);
698 8 : TALER_MERCHANT_get_orders_set_options (
699 : pos->ogh,
700 : TALER_MERCHANT_get_orders_option_h_contract (*h_contract));
701 8 : TALER_MERCHANT_get_orders_set_options (
702 : pos->ogh,
703 : TALER_MERCHANT_get_orders_option_timeout (pos->timeout),
704 : TALER_MERCHANT_get_orders_option_session_id (pos->session_id));
705 8 : if (pos->wait_for_refund)
706 4 : TALER_MERCHANT_get_orders_set_options (
707 : pos->ogh,
708 : TALER_MERCHANT_get_orders_option_min_refund (pos->refund_threshold));
709 : {
710 : enum TALER_ErrorCode ec;
711 :
712 8 : ec = TALER_MERCHANT_get_orders_start (
713 : pos->ogh,
714 : &wallet_poll_order_cb,
715 : pos);
716 8 : GNUNET_assert (TALER_EC_NONE == ec);
717 : }
718 : /* We CONTINUE to run the interpreter while the long-polled command
719 : completes asynchronously! */
720 8 : TALER_TESTING_interpreter_next (pos->is);
721 : }
722 :
723 :
724 : /**
725 : * Free the state of a "GET order" CMD, and possibly
726 : * cancel a pending operation thereof.
727 : *
728 : * @param cls closure.
729 : * @param cmd command being run.
730 : */
731 : static void
732 8 : wallet_poll_order_start_cleanup (void *cls,
733 : const struct TALER_TESTING_Command *cmd)
734 : {
735 8 : struct WalletPollOrderStartState *pos = cls;
736 :
737 8 : if (NULL != pos->ogh)
738 : {
739 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
740 : "Command `%s' was not terminated\n",
741 : TALER_TESTING_interpreter_get_current_label (
742 : pos->is));
743 0 : TALER_MERCHANT_get_orders_cancel (pos->ogh);
744 : }
745 8 : GNUNET_free (pos->already_paid_order_id);
746 8 : GNUNET_free (pos);
747 8 : }
748 :
749 :
750 : struct TALER_TESTING_Command
751 8 : TALER_TESTING_cmd_wallet_poll_order_start (
752 : const char *label,
753 : const char *merchant_url,
754 : const char *order_ref,
755 : struct GNUNET_TIME_Relative timeout,
756 : const char *await_refund)
757 : {
758 : struct WalletPollOrderStartState *pos;
759 :
760 8 : pos = GNUNET_new (struct WalletPollOrderStartState);
761 8 : pos->order_ref = order_ref;
762 8 : pos->merchant_url = merchant_url;
763 8 : pos->timeout = timeout;
764 8 : if (NULL != await_refund)
765 : {
766 4 : pos->wait_for_refund = true;
767 4 : GNUNET_assert (GNUNET_OK ==
768 : TALER_string_to_amount (await_refund,
769 : &pos->refund_threshold));
770 : }
771 : {
772 8 : struct TALER_TESTING_Command cmd = {
773 : .cls = pos,
774 : .label = label,
775 : .run = &wallet_poll_order_start_run,
776 : .cleanup = &wallet_poll_order_start_cleanup
777 : };
778 :
779 8 : return cmd;
780 : }
781 : }
782 :
783 :
784 : struct TALER_TESTING_Command
785 2 : TALER_TESTING_cmd_wallet_poll_order_start2 (
786 : const char *label,
787 : const char *merchant_url,
788 : const char *order_ref,
789 : struct GNUNET_TIME_Relative timeout,
790 : const char *await_refund,
791 : const char *session_id)
792 : {
793 : struct WalletPollOrderStartState *pos;
794 : struct TALER_TESTING_Command cmd;
795 :
796 2 : cmd = TALER_TESTING_cmd_wallet_poll_order_start (label,
797 : merchant_url,
798 : order_ref,
799 : timeout,
800 : await_refund);
801 2 : pos = cmd.cls;
802 2 : pos->session_id = session_id;
803 2 : return cmd;
804 : }
805 :
806 :
807 : /**
808 : * Run the "GET order conclude" CMD.
809 : *
810 : * @param cls closure.
811 : * @param cmd command being run now.
812 : * @param is interpreter state.
813 : */
814 : static void
815 8 : wallet_poll_order_conclude_run (void *cls,
816 : const struct TALER_TESTING_Command *cmd,
817 : struct TALER_TESTING_Interpreter *is)
818 : {
819 8 : struct WalletPollOrderConcludeState *poc = cls;
820 : const struct TALER_TESTING_Command *poll_cmd;
821 : struct WalletPollOrderStartState *pos;
822 :
823 8 : poc->is = is;
824 : poll_cmd =
825 8 : TALER_TESTING_interpreter_lookup_command (is,
826 : poc->start_reference);
827 8 : if (NULL == poll_cmd)
828 0 : TALER_TESTING_FAIL (poc->is);
829 8 : GNUNET_assert (poll_cmd->run == &wallet_poll_order_start_run);
830 8 : pos = poll_cmd->cls;
831 8 : pos->cs = poc;
832 8 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
833 : "Waiting on GET /orders/$ID of %s (%s)\n",
834 : poc->start_reference,
835 : (NULL == pos->ogh)
836 : ? "finished"
837 : : "active");
838 8 : if (NULL == pos->ogh)
839 4 : poc->task = GNUNET_SCHEDULER_add_now (&conclude_task,
840 : poc);
841 : else
842 4 : poc->task = GNUNET_SCHEDULER_add_at (pos->deadline,
843 : &conclude_task,
844 : poc);
845 : }
846 :
847 :
848 : /**
849 : * Free the state of a "GET order" CMD, and possibly
850 : * cancel a pending operation thereof.
851 : *
852 : * @param cls closure.
853 : * @param cmd command being run.
854 : */
855 : static void
856 8 : wallet_poll_order_conclude_cleanup (void *cls,
857 : const struct TALER_TESTING_Command *cmd)
858 : {
859 8 : struct WalletPollOrderConcludeState *poc = cls;
860 :
861 8 : if (NULL != poc->task)
862 : {
863 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
864 : "Command `%s' was not terminated\n",
865 : TALER_TESTING_interpreter_get_current_label (
866 : poc->is));
867 0 : GNUNET_SCHEDULER_cancel (poc->task);
868 0 : poc->task = NULL;
869 : }
870 8 : GNUNET_free (poc);
871 8 : }
872 :
873 :
874 : struct TALER_TESTING_Command
875 8 : TALER_TESTING_cmd_wallet_poll_order_conclude (
876 : const char *label,
877 : unsigned int expected_http_status,
878 : const char *expected_refund_amount,
879 : const char *poll_start_reference)
880 : {
881 : struct WalletPollOrderConcludeState *cps;
882 :
883 8 : cps = GNUNET_new (struct WalletPollOrderConcludeState);
884 8 : cps->start_reference = poll_start_reference;
885 8 : cps->expected_http_status = expected_http_status;
886 8 : if (NULL != expected_refund_amount)
887 : {
888 4 : cps->expected_refund = true;
889 4 : GNUNET_assert (GNUNET_OK ==
890 : TALER_string_to_amount (expected_refund_amount,
891 : &cps->expected_refund_amount));
892 : }
893 : {
894 8 : struct TALER_TESTING_Command cmd = {
895 : .cls = cps,
896 : .label = label,
897 : .run = &wallet_poll_order_conclude_run,
898 : .cleanup = &wallet_poll_order_conclude_cleanup
899 : };
900 :
901 8 : return cmd;
902 : }
903 : }
904 :
905 :
906 : struct TALER_TESTING_Command
907 2 : TALER_TESTING_cmd_wallet_poll_order_conclude2 (
908 : const char *label,
909 : unsigned int expected_http_status,
910 : const char *expected_refund_amount,
911 : const char *poll_start_reference,
912 : const char *already_paid_order_id)
913 : {
914 : struct WalletPollOrderConcludeState *cps;
915 : struct TALER_TESTING_Command cmd;
916 :
917 2 : cmd = TALER_TESTING_cmd_wallet_poll_order_conclude (
918 : label,
919 : expected_http_status,
920 : expected_refund_amount,
921 : poll_start_reference);
922 2 : cps = cmd.cls;
923 2 : cps->already_paid_order_id = already_paid_order_id;
924 2 : return cmd;
925 : }
926 :
927 :
928 : /* end of testing_api_cmd_wallet_get_order.c */
|