Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-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 : /**
21 : * @file testing_api_cmd_tip_authorize.c
22 : * @brief command to test the tipping.
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 : /**
34 : * State for a /tip-authorize CMD.
35 : */
36 : struct TipAuthorizeState
37 : {
38 :
39 : /**
40 : * Merchant base URL.
41 : */
42 : const char *merchant_url;
43 :
44 : /**
45 : * Expected HTTP response code.
46 : */
47 : unsigned int http_status;
48 :
49 : /**
50 : * Reference to the reserv to authorize the tip
51 : * from (if NULL, the merchant decides).
52 : */
53 : const char *reserve_reference;
54 :
55 : /**
56 : * Human-readable justification for the
57 : * tip authorization carried on by this CMD.
58 : */
59 : const char *justification;
60 :
61 : /**
62 : * Amount that should be authorized for tipping.
63 : */
64 : struct TALER_Amount amount;
65 :
66 : /**
67 : * Expected Taler error code for this CMD.
68 : */
69 : enum TALER_ErrorCode expected_ec;
70 :
71 : /**
72 : * Tip taler:// URI.
73 : */
74 : char *tip_uri;
75 :
76 : /**
77 : * The tip id; set when the CMD succeeds.
78 : */
79 : struct TALER_TipIdentifierP tip_id;
80 :
81 : /**
82 : * Expiration date for this tip.
83 : */
84 : struct GNUNET_TIME_Timestamp tip_expiration;
85 :
86 : /**
87 : * Handle to the on-going /tip-authorize request.
88 : */
89 : struct TALER_MERCHANT_TipAuthorizeHandle *tao;
90 :
91 : /**
92 : * The interpreter state.
93 : */
94 : struct TALER_TESTING_Interpreter *is;
95 :
96 : /**
97 : * Task used for retries.
98 : */
99 : struct GNUNET_SCHEDULER_Task *retry_task;
100 :
101 : /**
102 : * How long do we wait between retries?
103 : */
104 : struct GNUNET_TIME_Relative backoff;
105 :
106 : /**
107 : * How many retries are left?
108 : */
109 : unsigned int retries_left;
110 :
111 : };
112 :
113 :
114 : /**
115 : * Run the main logic of talking to the merchant.
116 : *
117 : * @param cls a `struct TipAuthorizeState`.
118 : */
119 : static void
120 : do_retry (void *cls);
121 :
122 :
123 : /**
124 : * Callback for a /tip-authorize request. Set into the state
125 : * what was returned from the backend (@a tip_id and @a
126 : * tip_expiration).
127 : *
128 : * @param cls closure
129 : * @param hr HTTP response we got
130 : * @param tip_id unique identifier for the tip
131 : * @param taler_tip_uri URI to let the wallet know about the tip
132 : * @param expiration when the tip expires
133 : */
134 : static void
135 0 : tip_authorize_cb (void *cls,
136 : const struct TALER_MERCHANT_HttpResponse *hr,
137 : struct TALER_TipIdentifierP *tip_id,
138 : const char *taler_tip_uri,
139 : struct GNUNET_TIME_Timestamp expiration)
140 : {
141 0 : struct TipAuthorizeState *tas = cls;
142 :
143 0 : tas->tao = NULL;
144 0 : if (tas->http_status != hr->http_status)
145 : {
146 0 : if ( (MHD_HTTP_NOT_FOUND == hr->http_status) &&
147 0 : (0 < tas->retries_left) )
148 : {
149 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
150 : "Reserve authorization failed. Reserve may not yet be ready, retrying %u more times.\n",
151 : tas->retries_left);
152 0 : tas->retries_left--;
153 0 : tas->backoff = GNUNET_TIME_randomized_backoff (tas->backoff,
154 : GNUNET_TIME_UNIT_SECONDS);
155 0 : tas->retry_task = GNUNET_SCHEDULER_add_delayed (tas->backoff,
156 : &do_retry,
157 : tas);
158 0 : return;
159 : }
160 :
161 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
162 : "Unexpected response code %u (%d) to command %s\n",
163 : hr->http_status,
164 : hr->ec,
165 : TALER_TESTING_interpreter_get_current_label (tas->is));
166 0 : TALER_TESTING_interpreter_fail (tas->is);
167 0 : return;
168 : }
169 :
170 0 : if (tas->expected_ec != hr->ec)
171 : {
172 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
173 : "Unexpected error code %d (%u) to command %s\n",
174 : (int) hr->ec,
175 : hr->http_status,
176 : TALER_TESTING_interpreter_get_current_label (tas->is));
177 0 : TALER_TESTING_interpreter_fail (tas->is);
178 0 : return;
179 : }
180 0 : if ( (MHD_HTTP_OK == hr->http_status) &&
181 0 : (TALER_EC_NONE == hr->ec) )
182 : {
183 0 : tas->tip_uri = strdup (taler_tip_uri);
184 0 : tas->tip_id = *tip_id;
185 0 : tas->tip_expiration = expiration;
186 : }
187 0 : TALER_TESTING_interpreter_next (tas->is);
188 : }
189 :
190 :
191 : /**
192 : * Offers information from the /tip-authorize CMD state to other
193 : * commands.
194 : *
195 : * @param cls closure
196 : * @param[out] ret result (could be anything)
197 : * @param trait name of the trait
198 : * @param index index number of the object to extract.
199 : * @return #GNUNET_OK on success
200 : */
201 : static enum GNUNET_GenericReturnValue
202 0 : tip_authorize_traits (void *cls,
203 : const void **ret,
204 : const char *trait,
205 : unsigned int index)
206 : {
207 0 : struct TipAuthorizeState *tas = cls;
208 : struct TALER_TESTING_Trait traits[] = {
209 0 : TALER_TESTING_make_trait_tip_id (&tas->tip_id),
210 0 : TALER_TESTING_make_trait_amount (&tas->amount),
211 0 : TALER_TESTING_make_trait_reason (&tas->justification),
212 0 : TALER_TESTING_make_trait_timestamp (0,
213 0 : &tas->tip_expiration),
214 0 : TALER_TESTING_trait_end (),
215 : };
216 :
217 0 : return TALER_TESTING_get_trait (traits,
218 : ret,
219 : trait,
220 : index);
221 : }
222 :
223 :
224 : /**
225 : * Runs the /tip-authorize CMD
226 : *
227 : * @param cls closure
228 : * @param cmd the CMD representing _this_ command
229 : * @param is interpreter state
230 : */
231 : static void
232 0 : tip_authorize_run (void *cls,
233 : const struct TALER_TESTING_Command *cmd,
234 : struct TALER_TESTING_Interpreter *is)
235 : {
236 0 : struct TipAuthorizeState *tas = cls;
237 :
238 0 : tas->retries_left = 16;
239 0 : tas->is = is;
240 0 : tas->retry_task = GNUNET_SCHEDULER_add_now (&do_retry,
241 : tas);
242 0 : }
243 :
244 :
245 : static void
246 0 : do_retry (void *cls)
247 : {
248 0 : struct TipAuthorizeState *tas = cls;
249 :
250 0 : tas->retry_task = NULL;
251 0 : if (NULL == tas->reserve_reference)
252 : {
253 0 : tas->tao = TALER_MERCHANT_tip_authorize (tas->is->ctx,
254 : tas->merchant_url,
255 : "http://merchant.com/pickup",
256 0 : &tas->amount,
257 : tas->justification,
258 : &tip_authorize_cb,
259 : tas);
260 : }
261 : else
262 : {
263 : const struct TALER_TESTING_Command *reserve_cmd;
264 : const struct TALER_ReservePublicKeyP *reserve_pub;
265 :
266 0 : reserve_cmd = TALER_TESTING_interpreter_lookup_command (
267 : tas->is,
268 : tas->reserve_reference);
269 0 : GNUNET_assert (GNUNET_OK ==
270 : TALER_TESTING_get_trait_reserve_pub (reserve_cmd,
271 : &reserve_pub));
272 0 : tas->tao = TALER_MERCHANT_tip_authorize2 (tas->is->ctx,
273 : tas->merchant_url,
274 : reserve_pub,
275 : "http://merchant.com/pickup",
276 0 : &tas->amount,
277 : tas->justification,
278 : &tip_authorize_cb,
279 : tas);
280 : }
281 0 : GNUNET_assert (NULL != tas->tao);
282 0 : }
283 :
284 :
285 : /**
286 : * Run the /tip-authorize CMD, the "fake" version of it.
287 : *
288 : * @param cls closure
289 : * @param cmd the CMD representing _this_ command
290 : * @param is interpreter state *
291 : */
292 : static void
293 0 : tip_authorize_fake_run (void *cls,
294 : const struct TALER_TESTING_Command *cmd,
295 : struct TALER_TESTING_Interpreter *is)
296 : {
297 0 : struct TipAuthorizeState *tas = cls;
298 :
299 : /* Make up a tip id. */
300 0 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
301 0 : &tas->tip_id,
302 : sizeof (struct TALER_TipIdentifierP));
303 0 : TALER_TESTING_interpreter_next (is);
304 0 : }
305 :
306 :
307 : /**
308 : * Free the state from a /tip-authorize CMD, and possibly
309 : * cancel any pending operation.
310 : *
311 : * @param cls closure
312 : * @param cmd the /tip-authorize CMD that is about to be freed.
313 : */
314 : static void
315 0 : tip_authorize_cleanup (void *cls,
316 : const struct TALER_TESTING_Command *cmd)
317 : {
318 0 : struct TipAuthorizeState *tas = cls;
319 :
320 0 : if (NULL != tas->tao)
321 : {
322 0 : TALER_LOG_WARNING ("Tip-autorize operation"
323 : " did not complete\n");
324 0 : TALER_MERCHANT_tip_authorize_cancel (tas->tao);
325 : }
326 0 : if (NULL != tas->retry_task)
327 : {
328 0 : GNUNET_SCHEDULER_cancel (tas->retry_task);
329 0 : tas->retry_task = NULL;
330 : }
331 0 : GNUNET_free (tas->tip_uri);
332 0 : GNUNET_free (tas);
333 0 : }
334 :
335 :
336 : struct TALER_TESTING_Command
337 0 : TALER_TESTING_cmd_tip_authorize_with_ec (const char *label,
338 : const char *merchant_url,
339 : const char *exchange_url,
340 : unsigned int http_status,
341 : const char *justification,
342 : const char *amount,
343 : enum TALER_ErrorCode ec)
344 : {
345 : struct TipAuthorizeState *tas;
346 :
347 0 : tas = GNUNET_new (struct TipAuthorizeState);
348 0 : tas->merchant_url = merchant_url;
349 0 : tas->justification = justification;
350 0 : tas->http_status = http_status;
351 0 : tas->expected_ec = ec;
352 0 : GNUNET_assert (GNUNET_OK ==
353 : TALER_string_to_amount (amount,
354 : &tas->amount));
355 : {
356 0 : struct TALER_TESTING_Command cmd = {
357 : .label = label,
358 : .cls = tas,
359 : .run = &tip_authorize_run,
360 : .cleanup = &tip_authorize_cleanup,
361 : .traits = &tip_authorize_traits
362 : };
363 :
364 0 : return cmd;
365 : }
366 : }
367 :
368 :
369 : struct TALER_TESTING_Command
370 0 : TALER_TESTING_cmd_tip_authorize_from_reserve_with_ec (
371 : const char *label,
372 : const char *merchant_url,
373 : const char *exchange_url,
374 : const char *reserve_reference,
375 : unsigned int http_status,
376 : const char *justification,
377 : const char *amount,
378 : enum TALER_ErrorCode ec)
379 : {
380 : struct TipAuthorizeState *tas;
381 :
382 0 : tas = GNUNET_new (struct TipAuthorizeState);
383 0 : tas->merchant_url = merchant_url;
384 0 : tas->justification = justification;
385 0 : tas->http_status = http_status;
386 0 : tas->expected_ec = ec;
387 0 : tas->reserve_reference = reserve_reference;
388 0 : GNUNET_assert (GNUNET_OK ==
389 : TALER_string_to_amount (amount,
390 : &tas->amount));
391 : {
392 0 : struct TALER_TESTING_Command cmd = {
393 : .label = label,
394 : .cls = tas,
395 : .run = &tip_authorize_run,
396 : .cleanup = &tip_authorize_cleanup,
397 : .traits = &tip_authorize_traits
398 : };
399 :
400 0 : return cmd;
401 : }
402 : }
403 :
404 :
405 : struct TALER_TESTING_Command
406 0 : TALER_TESTING_cmd_tip_authorize (const char *label,
407 : const char *merchant_url,
408 : const char *exchange_url,
409 : unsigned int http_status,
410 : const char *justification,
411 : const char *amount)
412 : {
413 : struct TipAuthorizeState *tas;
414 :
415 0 : tas = GNUNET_new (struct TipAuthorizeState);
416 0 : tas->merchant_url = merchant_url;
417 0 : tas->justification = justification;
418 0 : tas->http_status = http_status;
419 0 : GNUNET_assert (GNUNET_OK ==
420 : TALER_string_to_amount (amount,
421 : &tas->amount));
422 : {
423 0 : struct TALER_TESTING_Command cmd = {
424 : .label = label,
425 : .cls = tas,
426 : .run = &tip_authorize_run,
427 : .cleanup = &tip_authorize_cleanup,
428 : .traits = &tip_authorize_traits
429 : };
430 :
431 0 : return cmd;
432 : }
433 : }
434 :
435 :
436 : struct TALER_TESTING_Command
437 0 : TALER_TESTING_cmd_tip_authorize_from_reserve (const char *label,
438 : const char *merchant_url,
439 : const char *exchange_url,
440 : const char *reserve_reference,
441 : unsigned int http_status,
442 : const char *justification,
443 : const char *amount)
444 : {
445 : struct TipAuthorizeState *tas;
446 :
447 0 : tas = GNUNET_new (struct TipAuthorizeState);
448 0 : tas->merchant_url = merchant_url;
449 0 : tas->reserve_reference = reserve_reference;
450 0 : tas->justification = justification;
451 0 : tas->http_status = http_status;
452 0 : GNUNET_assert (GNUNET_OK ==
453 : TALER_string_to_amount (amount,
454 : &tas->amount));
455 : {
456 0 : struct TALER_TESTING_Command cmd = {
457 : .label = label,
458 : .cls = tas,
459 : .run = &tip_authorize_run,
460 : .cleanup = &tip_authorize_cleanup,
461 : .traits = &tip_authorize_traits
462 : };
463 :
464 0 : return cmd;
465 : }
466 : }
467 :
468 :
469 : struct TALER_TESTING_Command
470 0 : TALER_TESTING_cmd_tip_authorize_fake (const char *label)
471 : {
472 : struct TipAuthorizeState *tas;
473 :
474 0 : tas = GNUNET_new (struct TipAuthorizeState);
475 : {
476 0 : struct TALER_TESTING_Command cmd = {
477 : .label = label,
478 : .cls = tas,
479 : .run = &tip_authorize_fake_run,
480 : .cleanup = &tip_authorize_cleanup,
481 : .traits = &tip_authorize_traits
482 : };
483 :
484 0 : return cmd;
485 : }
486 : }
487 :
488 :
489 : /* end of testing_api_cmd_tip_authorize.c */
|