testing_api_cmd_purse_get.c (8374B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2022 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 testing/testing_api_cmd_purse_get.c 21 * @brief Implement the GET /purse/$RID test command. 22 * @author Marcello Stanisci 23 */ 24 #include "taler/platform.h" 25 #include "taler/taler_json_lib.h" 26 #include <gnunet/gnunet_curl_lib.h> 27 #include "taler/taler_testing_lib.h" 28 29 30 /** 31 * State for a "poll" CMD. 32 */ 33 struct PollState 34 { 35 36 /** 37 * How long do we give the exchange to respond? 38 */ 39 struct GNUNET_TIME_Relative timeout; 40 41 /** 42 * Label to the command which created the purse to check, 43 * needed to resort the purse key. 44 */ 45 const char *poll_reference; 46 47 /** 48 * Timeout to wait for at most. 49 */ 50 struct GNUNET_SCHEDULER_Task *tt; 51 52 /** 53 * The interpreter we are using. 54 */ 55 struct TALER_TESTING_Interpreter *is; 56 }; 57 58 59 /** 60 * State for a "status" CMD. 61 */ 62 struct StatusState 63 { 64 65 /** 66 * How long do we give the exchange to respond? 67 */ 68 struct GNUNET_TIME_Relative timeout; 69 70 /** 71 * Poller waiting for us. 72 */ 73 struct PollState *ps; 74 75 /** 76 * Label to the command which created the purse to check, 77 * needed to resort the purse key. 78 */ 79 const char *purse_reference; 80 81 /** 82 * Handle to the "purse status" operation. 83 */ 84 struct TALER_EXCHANGE_PurseGetHandle *pgh; 85 86 /** 87 * Expected purse balance. 88 */ 89 const char *expected_balance; 90 91 /** 92 * Public key of the purse being analyzed. 93 */ 94 const struct TALER_PurseContractPublicKeyP *purse_pub; 95 96 /** 97 * Interpreter state. 98 */ 99 struct TALER_TESTING_Interpreter *is; 100 101 /** 102 * Expected HTTP response code. 103 */ 104 unsigned int expected_response_code; 105 106 /** 107 * Are we waiting for a merge or a deposit? 108 */ 109 bool wait_for_merge; 110 111 }; 112 113 114 /** 115 * Check that the purse balance and HTTP response code are 116 * both acceptable. 117 * 118 * @param cls closure. 119 * @param rs HTTP response details 120 */ 121 static void 122 purse_status_cb (void *cls, 123 const struct TALER_EXCHANGE_PurseGetResponse *rs) 124 { 125 struct StatusState *ss = cls; 126 struct TALER_TESTING_Interpreter *is = ss->is; 127 128 ss->pgh = NULL; 129 if (ss->expected_response_code != rs->hr.http_status) 130 { 131 TALER_TESTING_unexpected_status (is, 132 rs->hr.http_status, 133 ss->expected_response_code); 134 return; 135 } 136 if (MHD_HTTP_OK == ss->expected_response_code) 137 { 138 struct TALER_Amount eb; 139 140 GNUNET_assert (GNUNET_OK == 141 TALER_string_to_amount (ss->expected_balance, 142 &eb)); 143 if (0 != TALER_amount_cmp (&eb, 144 &rs->details.ok.balance)) 145 { 146 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 147 "Unexpected amount in purse: %s\n", 148 TALER_amount_to_string (&rs->details.ok.balance)); 149 TALER_TESTING_interpreter_fail (ss->is); 150 return; 151 } 152 } 153 if (NULL != ss->ps) 154 { 155 /* force continuation on long poller */ 156 GNUNET_SCHEDULER_cancel (ss->ps->tt); 157 ss->ps->tt = NULL; 158 TALER_TESTING_interpreter_next (is); 159 return; 160 } 161 if (GNUNET_TIME_relative_is_zero (ss->timeout)) 162 TALER_TESTING_interpreter_next (is); 163 } 164 165 166 /** 167 * Run the command. 168 * 169 * @param cls closure. 170 * @param cmd the command being executed. 171 * @param is the interpreter state. 172 */ 173 static void 174 status_run (void *cls, 175 const struct TALER_TESTING_Command *cmd, 176 struct TALER_TESTING_Interpreter *is) 177 { 178 struct StatusState *ss = cls; 179 const struct TALER_TESTING_Command *create_purse; 180 181 ss->is = is; 182 create_purse 183 = TALER_TESTING_interpreter_lookup_command (is, 184 ss->purse_reference); 185 GNUNET_assert (NULL != create_purse); 186 if (GNUNET_OK != 187 TALER_TESTING_get_trait_purse_pub (create_purse, 188 &ss->purse_pub)) 189 { 190 GNUNET_break (0); 191 TALER_LOG_ERROR ("Failed to find purse_pub for status query\n"); 192 TALER_TESTING_interpreter_fail (is); 193 return; 194 } 195 ss->pgh = TALER_EXCHANGE_purse_get ( 196 TALER_TESTING_interpreter_get_context (is), 197 TALER_TESTING_get_exchange_url (is), 198 TALER_TESTING_get_keys (is), 199 ss->purse_pub, 200 ss->timeout, 201 ss->wait_for_merge, 202 &purse_status_cb, 203 ss); 204 if (! GNUNET_TIME_relative_is_zero (ss->timeout)) 205 { 206 TALER_TESTING_interpreter_next (is); 207 return; 208 } 209 } 210 211 212 /** 213 * Cleanup the state from a "purse status" CMD, and possibly 214 * cancel a pending operation thereof. 215 * 216 * @param cls closure. 217 * @param cmd the command which is being cleaned up. 218 */ 219 static void 220 status_cleanup (void *cls, 221 const struct TALER_TESTING_Command *cmd) 222 { 223 struct StatusState *ss = cls; 224 225 if (NULL != ss->pgh) 226 { 227 TALER_TESTING_command_incomplete (ss->is, 228 cmd->label); 229 TALER_EXCHANGE_purse_get_cancel (ss->pgh); 230 ss->pgh = NULL; 231 } 232 GNUNET_free (ss); 233 } 234 235 236 struct TALER_TESTING_Command 237 TALER_TESTING_cmd_purse_poll ( 238 const char *label, 239 unsigned int expected_http_status, 240 const char *purse_ref, 241 const char *expected_balance, 242 bool wait_for_merge, 243 struct GNUNET_TIME_Relative timeout) 244 { 245 struct StatusState *ss; 246 247 GNUNET_assert (NULL != purse_ref); 248 ss = GNUNET_new (struct StatusState); 249 ss->purse_reference = purse_ref; 250 ss->expected_balance = expected_balance; 251 ss->expected_response_code = expected_http_status; 252 ss->timeout = timeout; 253 ss->wait_for_merge = wait_for_merge; 254 { 255 struct TALER_TESTING_Command cmd = { 256 .cls = ss, 257 .label = label, 258 .run = &status_run, 259 .cleanup = &status_cleanup 260 }; 261 262 return cmd; 263 } 264 } 265 266 267 /** 268 * Long poller timed out. Fail the test. 269 * 270 * @param cls a `struct PollState` 271 */ 272 static void 273 finish_timeout (void *cls) 274 { 275 struct PollState *ps = cls; 276 277 ps->tt = NULL; 278 GNUNET_break (0); 279 TALER_TESTING_interpreter_fail (ps->is); 280 } 281 282 283 /** 284 * Run the command. 285 * 286 * @param cls closure. 287 * @param cmd the command being executed. 288 * @param is the interpreter state. 289 */ 290 static void 291 finish_run (void *cls, 292 const struct TALER_TESTING_Command *cmd, 293 struct TALER_TESTING_Interpreter *is) 294 { 295 struct PollState *ps = cls; 296 const struct TALER_TESTING_Command *poll_purse; 297 struct StatusState *ss; 298 299 ps->is = is; 300 poll_purse 301 = TALER_TESTING_interpreter_lookup_command (is, 302 ps->poll_reference); 303 GNUNET_assert (NULL != poll_purse); 304 GNUNET_assert (poll_purse->run == &status_run); 305 ss = poll_purse->cls; 306 if (NULL == ss->pgh) 307 { 308 TALER_TESTING_interpreter_next (is); 309 return; 310 } 311 GNUNET_assert (NULL == ss->ps); 312 ss->ps = ps; 313 ps->tt = GNUNET_SCHEDULER_add_delayed (ps->timeout, 314 &finish_timeout, 315 ps); 316 } 317 318 319 /** 320 * Cleanup the state from a "purse finish" CMD. 321 * 322 * @param cls closure. 323 * @param cmd the command which is being cleaned up. 324 */ 325 static void 326 finish_cleanup (void *cls, 327 const struct TALER_TESTING_Command *cmd) 328 { 329 struct PollState *ps = cls; 330 331 if (NULL != ps->tt) 332 { 333 GNUNET_SCHEDULER_cancel (ps->tt); 334 ps->tt = NULL; 335 } 336 GNUNET_free (ps); 337 } 338 339 340 struct TALER_TESTING_Command 341 TALER_TESTING_cmd_purse_poll_finish (const char *label, 342 struct GNUNET_TIME_Relative timeout, 343 const char *poll_reference) 344 { 345 struct PollState *ps; 346 347 GNUNET_assert (NULL != poll_reference); 348 ps = GNUNET_new (struct PollState); 349 ps->timeout = timeout; 350 ps->poll_reference = poll_reference; 351 { 352 struct TALER_TESTING_Command cmd = { 353 .cls = ps, 354 .label = label, 355 .run = &finish_run, 356 .cleanup = &finish_cleanup 357 }; 358 359 return cmd; 360 } 361 }