gnunet_testing_lib.h (29342B)
1 /* 2 This file is part of GNUnet 3 Copyright (C) 2021, 2023, 2024 GNUnet e.V. 4 5 GNUnet is free software: you can redistribute it and/or modify it 6 under the terms of the GNU Affero General Public License as published 7 by the Free Software Foundation, either version 3 of the License, 8 or (at your option) any later version. 9 10 GNUnet 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 GNU 13 Affero General Public License for more details. 14 15 You should have received a copy of the GNU Affero General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 SPDX-License-Identifier: AGPL3.0-or-later 19 */ 20 21 /** 22 * @brief Central interpreter and command loop for writing an interpreter to test asynchronous systems 23 * @author Christian Grothoff <christian@grothoff.org> 24 * @author Marcello Stanisci 25 * @author t3sserakt 26 */ 27 #ifndef GNUNET_TESTING_LIB_H 28 #define GNUNET_TESTING_LIB_H 29 30 #include "gnunet_util_lib.h" 31 32 /** 33 * Maximum length of label in command 34 */ 35 #define GNUNET_TESTING_CMD_MAX_LABEL_LENGTH 127 36 37 /* ********************* Helper functions ********************* */ 38 39 /** 40 * Print failing line number and trigger shutdown. Useful 41 * quite any time after the command "run" method has been called. 42 * Returns from the current function. 43 */ 44 #define GNUNET_TESTING_FAIL(is) \ 45 do { \ 46 GNUNET_break (0); \ 47 GNUNET_TESTING_interpreter_fail (is); \ 48 return; \ 49 } while (0) 50 51 52 /** 53 * Log an error message about a command not having run to completion. 54 * 55 * @param is interpreter 56 * @param label command label of the incomplete command 57 */ 58 #define GNUNET_TESTING_command_incomplete(is,label) \ 59 do { \ 60 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \ 61 "Command %s (%s:%u) did not complete (at %s)\n", \ 62 label, \ 63 __FILE__, \ 64 __LINE__, \ 65 GNUNET_TESTING_interpreter_current_cmd_get_label (is)); \ 66 } while (0) 67 68 69 /* ******************* Generic interpreter logic ************ */ 70 71 /** 72 * Global state of the interpreter, used by a command 73 * to access information about other commands. 74 */ 75 struct GNUNET_TESTING_Interpreter; 76 77 /** 78 * State each asynchronous command must have in its closure. 79 */ 80 struct GNUNET_TESTING_AsyncContext 81 { 82 83 /** 84 * Interpreter we are part of. Initialized when 85 * the global interpreter starts. 86 */ 87 struct GNUNET_TESTING_Interpreter *is; 88 89 /** 90 * Function to call when async operation is done. 91 */ 92 GNUNET_SCHEDULER_TaskCallback notify_finished; 93 94 /** 95 * Closure for @e notify_finished. 96 */ 97 void *notify_finished_cls; 98 99 /** 100 * Indication if the command finished (#GNUNET_OK). 101 * #GNUNET_NO if it did not finish, 102 * #GNUNET_SYSERR if it failed. 103 */ 104 enum GNUNET_GenericReturnValue finished; 105 106 /** 107 * Set to true if interpreter_next() has already been 108 * called for this command. 109 */ 110 bool next_called; 111 }; 112 113 114 /** 115 * The asynchronous command of @a ac has failed. 116 * 117 * @param ac command-specific context 118 */ 119 void 120 GNUNET_TESTING_async_fail ( 121 struct GNUNET_TESTING_AsyncContext *ac); 122 123 124 /** 125 * The asynchronous command of @a ac has finished. 126 * 127 * @param ac command-specific context 128 */ 129 void 130 GNUNET_TESTING_async_finish ( 131 struct GNUNET_TESTING_AsyncContext *ac); 132 133 134 /** 135 * Signature of a function used to start executing a command of a test. Runs 136 * the command. Note that upon return, the interpreter will not automatically 137 * run the next command if this is an asynchronous command unless the command 138 * was wrapped in #GNUNET_TESTING_cmd_make_unblocking(), as the command may 139 * then continue asynchronously in other scheduler tasks. In this case, 140 * #GNUNET_TESTING_async_finish() must be called to run the next task. 141 * 142 * @param cls closure 143 * @param is interpreter running the command 144 */ 145 typedef void 146 (*GNUNET_TESTING_CommandRunRoutine)( 147 void *cls, 148 struct GNUNET_TESTING_Interpreter *is); 149 150 151 /** 152 * Signature of a function used to clean up resources allocated 153 * by a command. 154 * 155 * @param cls closure 156 */ 157 typedef void 158 (*GNUNET_TESTING_CommandCleanupRoutine)(void *cls); 159 160 161 /** 162 * Signature of a function used to extract traits exposed by a 163 * command. 164 * 165 * @param cls closure 166 * @param[out] ret where to return the trait data 167 * @param trait name of the trait to return 168 * @param index index of the trait (for traits that are indexed) 169 * @return #GNUNET_OK on success 170 */ 171 typedef enum GNUNET_GenericReturnValue 172 (*GNUNET_TESTING_CommandGetTraits) (void *cls, 173 const void **ret, 174 const char *trait, 175 unsigned int index); 176 177 /** 178 * Create a new command that may be asynchronous. 179 * 180 * @param cls the closure 181 * @param label the Label. Maximum length is #GNUNET_TESTING_CMD_MAX_LABEL_LENGTH 182 * @param run the run routing 183 * @param cleanup the cleanup function 184 * @param traits the traits function (optional) 185 * @param ac the async context, NULL if command is always 186 * synchronous 187 * @return the command the function cannot fail 188 */ 189 struct GNUNET_TESTING_Command 190 GNUNET_TESTING_command_new_ac ( 191 void *cls, 192 const char *label, 193 GNUNET_TESTING_CommandRunRoutine run, 194 GNUNET_TESTING_CommandCleanupRoutine cleanup, 195 GNUNET_TESTING_CommandGetTraits traits, 196 struct GNUNET_TESTING_AsyncContext *ac); 197 198 199 /** 200 * Create a new command 201 * 202 * @param cls the closure 203 * @param label the Label. Maximum length is #GNUNET_TESTING_CMD_MAX_LABEL_LENGTH 204 * @param run the run routing 205 * @param cleanup the cleanup function 206 * @param traits the traits function (optional) 207 * @return the command the function cannot fail 208 */ 209 #define GNUNET_TESTING_command_new(cls,label,run,cleanup,traits) \ 210 GNUNET_TESTING_command_new_ac (cls,label,run,cleanup,traits,NULL) 211 212 213 /** 214 * Structure with storage space for a label. 215 */ 216 struct GNUNET_TESTING_CommandLabel 217 { 218 char value[GNUNET_TESTING_CMD_MAX_LABEL_LENGTH + 1]; 219 }; 220 221 222 /** 223 * Set @a label to @a value. Asserts that @a value is 224 * not longer than #GNUNET_TESTING_CMD_MAX_LABEL_LENGTH. 225 * 226 * @param[out] label label to initialize 227 * @param value value to store into @a label 228 */ 229 void 230 GNUNET_TESTING_set_label ( 231 struct GNUNET_TESTING_CommandLabel *label, 232 const char *value); 233 234 235 /** 236 * A command to be run by the interpreter. 237 */ 238 struct GNUNET_TESTING_Command 239 { 240 241 /** 242 * Label for the command. 243 */ 244 struct GNUNET_TESTING_CommandLabel label; 245 246 /** 247 * Closure for all commands with command-specific context information. 248 */ 249 void *cls; 250 251 /** 252 * Variable name for the command, NULL for none. 253 */ 254 const char *name; 255 256 /** 257 * Runs the command. Note that upon return, the interpreter 258 * will not automatically run the next command, as the command 259 * may continue asynchronously in other scheduler tasks. Thus, 260 * the command must ensure to eventually call 261 * #GNUNET_TESTING_interpreter_next() or 262 * #GNUNET_TESTING_interpreter_fail(). 263 * 264 * If this function creates some asynchronous activity, it should 265 * initialize @e finish to a function that can be used to wait for 266 * the asynchronous activity to terminate. 267 * 268 * @param cls closure 269 * @param is interpreter state 270 */ 271 GNUNET_TESTING_CommandRunRoutine run; 272 273 /** 274 * Pointer to the asynchronous context in the command's 275 * closure. Used by the 276 * #GNUNET_TESTING_async_finish() and 277 * #GNUNET_TESTING_async_fail() functions. 278 * 279 * Must be NULL if a command is synchronous. 280 */ 281 struct GNUNET_TESTING_AsyncContext *ac; 282 283 /** 284 * Clean up after the command. Run during forced termination 285 * (CTRL-C) or test failure or test success. 286 * 287 * @param cls closure 288 */ 289 GNUNET_TESTING_CommandCleanupRoutine cleanup; 290 291 /** 292 * Extract information from a command that is useful for other 293 * commands. Can be NULL if a command has no traits. 294 * 295 * @param cls closure 296 * @param[out] ret result (could be anything) 297 * @param trait name of the trait 298 * @param index index number of the object to extract. 299 * @return #GNUNET_OK on success, 300 * #GNUNET_NO if no trait was found 301 */ 302 GNUNET_TESTING_CommandGetTraits traits; 303 304 /** 305 * When did the execution of this command start? 306 */ 307 struct GNUNET_TIME_Absolute start_time; 308 309 /** 310 * When did the execution of this command finish? 311 */ 312 struct GNUNET_TIME_Absolute finish_time; 313 314 /** 315 * When did we start the last run of this command? Delta to @e finish_time 316 * gives the latency for the last successful run. Useful in case @e 317 * num_tries was positive and the command was run multiple times. In that 318 * case, the @e start_time gives the time when we first tried to run the 319 * command, so the difference between @e start_time and @e finish_time would 320 * be the time all of the @e num_tries took, while the delta to @e 321 * last_req_time is the time the last (successful) execution took. 322 */ 323 struct GNUNET_TIME_Absolute last_req_time; 324 325 /** 326 * How often did we try to execute this command? (In case it is a request 327 * that is repated.) Note that a command must have some built-in retry 328 * mechanism for this value to be useful. 329 */ 330 unsigned int num_tries; 331 332 /** 333 * If "true", the interpreter should not immediately run the next command, 334 * even if this command did not complete via #GNUNET_TESTING_async_finish(). 335 * Otherwise, #GNUNET_TESTING_cmd_finish() must be used to ensure that a 336 * command actually completed. 337 */ 338 bool asynchronous_finish; 339 340 }; 341 342 343 /** 344 * Lookup command by label. 345 * 346 * @param is interpreter to lookup command in 347 * @param label label of the command to lookup. 348 * @return the command, if it is found, or NULL. 349 */ 350 const struct GNUNET_TESTING_Command * 351 GNUNET_TESTING_interpreter_lookup_command ( 352 struct GNUNET_TESTING_Interpreter *is, 353 const char *label); 354 355 356 /** 357 * Get command from hash map by variable name. 358 * 359 * @param is interpreter state. 360 * @param name name of the variable to get command by 361 * @return the command, if it is found, or NULL. 362 */ 363 const struct GNUNET_TESTING_Command * 364 GNUNET_TESTING_interpreter_get_command ( 365 struct GNUNET_TESTING_Interpreter *is, 366 const char *name); 367 368 369 /** 370 * Update the last request time of the current command 371 * to the current time. 372 * 373 * @param[in,out] is interpreter state where to show 374 * that we are doing something 375 */ 376 void 377 GNUNET_TESTING_interpreter_current_cmd_touch ( 378 struct GNUNET_TESTING_Interpreter *is); 379 380 381 /** 382 * Increment the 'num_tries' counter for the current command. 383 * 384 * @param[in,out] is interpreter state where to 385 * increment the counter 386 */ 387 void 388 GNUNET_TESTING_interpreter_current_cmd_inc_tries ( 389 struct GNUNET_TESTING_Interpreter *is); 390 391 392 /** 393 * Obtain label of the command being now run. 394 * 395 * @param is interpreter state. 396 * @return the label. 397 */ 398 const char * 399 GNUNET_TESTING_interpreter_current_cmd_get_label ( 400 struct GNUNET_TESTING_Interpreter *is); 401 402 403 /** 404 * Current command failed, clean up and fail the test case. 405 * 406 * @param is interpreter state. 407 */ 408 void 409 GNUNET_TESTING_interpreter_fail ( 410 struct GNUNET_TESTING_Interpreter *is); 411 412 413 /** 414 * Skips the current test, the environment is 415 * not prepared correctly. 416 * 417 * @param is interpreter state. 418 */ 419 void 420 GNUNET_TESTING_interpreter_skip ( 421 struct GNUNET_TESTING_Interpreter *is); 422 423 424 /** 425 * Callback over commands of an interpreter. 426 * 427 * @param cls closure 428 * @param cmd a command to process 429 */ 430 typedef void 431 (*GNUNET_TESTING_CommandIterator)( 432 void *cls, 433 const struct GNUNET_TESTING_Command *cmd); 434 435 436 /** 437 * Iterates over all of the top-level commands of an 438 * interpreter. 439 * 440 * @param[in] is interpreter to iterate over 441 * @param asc true in execution order, false for reverse execution order 442 * @param cb function to call on each command 443 * @param cb_cls closure for cb 444 */ 445 void 446 GNUNET_TESTING_interpreter_commands_iterate ( 447 struct GNUNET_TESTING_Interpreter *is, 448 bool asc, 449 GNUNET_TESTING_CommandIterator cb, 450 void *cb_cls); 451 452 453 /* ************** Fundamental interpreter commands ************ */ 454 455 456 /** 457 * Create command array terminator. 458 * 459 * @return a end-command. 460 */ 461 struct GNUNET_TESTING_Command 462 GNUNET_TESTING_cmd_end (void); 463 464 465 /** 466 * Create a "batch" command. Such command takes a end_CMD-terminated array of 467 * CMDs and executed them. Once it hits the end CMD, it passes the control to 468 * the next top-level CMD, regardless of it being another batch or ordinary 469 * CMD. 470 * 471 * @param label the command label. 472 * @param batch array of CMDs to execute. 473 * @return the command. 474 */ 475 struct GNUNET_TESTING_Command 476 GNUNET_TESTING_cmd_batch ( 477 const char *label, 478 struct GNUNET_TESTING_Command *batch); 479 480 481 /** 482 * Performance counter. 483 */ 484 struct GNUNET_TESTING_Timer 485 { 486 /** 487 * For which type of commands. 488 */ 489 const char *prefix; 490 491 /** 492 * Total time spend in all commands of this type. 493 */ 494 struct GNUNET_TIME_Relative total_duration; 495 496 /** 497 * Total time spend waiting for the *successful* execution 498 * in all commands of this type. 499 */ 500 struct GNUNET_TIME_Relative success_latency; 501 502 /** 503 * Number of commands summed up. 504 */ 505 unsigned int num_commands; 506 507 /** 508 * Number of retries summed up. 509 */ 510 unsigned int num_retries; 511 }; 512 513 /** 514 * Obtain performance data from the interpreter. 515 * 516 * @param label command label. 517 * @param[in,out] timers NULL-prefix terminated array that specifies what commands (by label) to obtain runtimes for 518 * @return the command 519 */ 520 struct GNUNET_TESTING_Command 521 GNUNET_TESTING_cmd_stat ( 522 const char *label, 523 struct GNUNET_TESTING_Timer *timers); 524 525 526 /** 527 * Set variable to command as side-effect of 528 * running a command. 529 * 530 * @param name name of the variable to set 531 * @param cmd command to set to variable when run 532 * @return modified command 533 */ 534 struct GNUNET_TESTING_Command 535 GNUNET_TESTING_cmd_set_var ( 536 const char *name, 537 struct GNUNET_TESTING_Command cmd); 538 539 540 /** 541 * Command to create a barrier. 542 * 543 * @param label The label of this command. 544 * @param number_to_be_reached If this number of processes reached 545 * this barrier, all processes waiting at 546 * this barrier can pass it. 547 */ 548 struct GNUNET_TESTING_Command 549 GNUNET_TESTING_cmd_barrier_create ( 550 const char *label, 551 unsigned int number_to_be_reached); 552 553 554 /** 555 * If this command is executed the the process is signaling the master process 556 * that it reached a barrier. If this command is synchronous it will block. 557 * 558 * @param label name for command. 559 * @param barrier_label The name of the barrier we waited for and which was reached. 560 * @return command. 561 */ 562 struct GNUNET_TESTING_Command 563 GNUNET_TESTING_cmd_barrier_reached ( 564 const char *label, 565 const char *barrier_label); 566 567 568 #define GNUNET_TESTING_NETJAIL_START_SCRIPT "netjail_start_new.sh" 569 570 #define GNUNET_TESTING_NETJAIL_STOP_SCRIPT "netjail_stop.sh" 571 572 /** 573 * Create command. 574 * 575 * @param label Name for the command. 576 * @param topology_data topology data 577 * @param timeout Before this timeout is reached this cmd MUST finish. 578 * @return command. 579 */ 580 struct GNUNET_TESTING_Command 581 GNUNET_TESTING_cmd_netjail_start_helpers ( 582 const char *label, 583 const char *topology_cmd_label, 584 struct GNUNET_TIME_Relative timeout); 585 586 587 /** 588 * This command executes a shell script to setup the netjail environment. 589 * 590 * @param label name for command. 591 * @param script which script to run, e.g. #GNUNET_TESTING_NETJAIL_START_SCRIPT 592 * @param topology_config Configuration file for the test topology. 593 * @param read_file Flag indicating if the the name of the topology file is send to the helper, or a string with the topology data. 594 * @return command. 595 */ 596 struct GNUNET_TESTING_Command 597 GNUNET_TESTING_cmd_netjail_setup ( 598 const char *label, 599 const char *script, 600 const char *topology_cmd_label); 601 602 603 struct GNUNET_TESTING_Command 604 GNUNET_TESTING_cmd_load_topology_from_file ( 605 const char *label, 606 const char *filename); 607 608 609 struct GNUNET_TESTING_Command 610 GNUNET_TESTING_cmd_load_topology_from_string ( 611 const char *label, 612 const char *topology_data); 613 614 615 /** 616 * Turn asynchronous command into non-blocking command by setting 617 * asynchronous_finish to true. Modifies (and then returns) @a cmd simply 618 * setting the bit. By default, most commands are blocking, and by wrapping 619 * the command construction in this function a blocking command can be turned 620 * into an asynchronous command where the interpreter continues after 621 * initiating the asynchronous action. Does nothing if the command is 622 * fundamentally synchronous. 623 * 624 * @param[in,out] cmd command to make non-blocking 625 * @return a finish-command. 626 */ 627 struct GNUNET_TESTING_Command 628 GNUNET_TESTING_cmd_make_unblocking ( 629 struct GNUNET_TESTING_Command cmd); 630 631 632 /** 633 * Create (synchronous) command that waits for another command to finish. 634 * If @a cmd_ref did not finish after @a timeout, this command will fail 635 * the test case. 636 * 637 * @param finish_label label for this command 638 * @param cmd_ref reference to a previous command which we should 639 * wait for (call `finish()` on) 640 * @param timeout how long to wait at most for @a cmd_ref to finish 641 * @return a finish-command. 642 */ 643 struct GNUNET_TESTING_Command 644 GNUNET_TESTING_cmd_finish ( 645 const char *finish_label, 646 const char *cmd_ref, 647 struct GNUNET_TIME_Relative timeout); 648 649 650 /** 651 * Create a "signal" CMD. 652 * 653 * @param label command label. 654 * @param process_label label of a command that has a process trait 655 * @param signal signal to send to @a process. 656 * @return the command. 657 */ 658 struct GNUNET_TESTING_Command 659 GNUNET_TESTING_cmd_signal ( 660 const char *label, 661 const char *process_label, 662 int signal); 663 664 665 /** 666 * Sleep for @a duration. 667 * 668 * @param label command label. 669 * @param duration time to sleep 670 * @return the command. 671 */ 672 struct GNUNET_TESTING_Command 673 GNUNET_TESTING_cmd_sleep ( 674 const char *label, 675 struct GNUNET_TIME_Relative duration); 676 677 678 /** 679 * Command to execute a command. 680 * 681 * @param label Label of the command. 682 */ 683 struct GNUNET_TESTING_Command 684 GNUNET_TESTING_cmd_exec ( 685 const char *label, 686 enum GNUNET_OS_ProcessStatusType expected_type, 687 unsigned long int expected_exit_code, 688 char *const script_argv[]); 689 690 691 /** 692 * Command to execute a command. 693 * 694 * @param label Label of the command. 695 */ 696 struct GNUNET_TESTING_Command 697 GNUNET_TESTING_cmd_exec_va ( 698 const char *label, 699 enum GNUNET_OS_ProcessStatusType expected_type, 700 unsigned long int expected_exit_code, 701 ...); 702 703 704 /** 705 * Make the instruction pointer point to @a target_label 706 * only if @a counter is greater than zero. Note that 707 * the command that will be executed next in this case 708 * is the one AFTER @a target_label, as the command we 709 * jump to is skipped by the advancing IP after the 710 * rewind. 711 * 712 * @param label command label 713 * @param target_label label of the new instruction pointer's destination after the jump; 714 * must be before the current instruction (and the command at the @a target_label itself will not be run, but the one afterwards) 715 * @param counter counts how many times the rewinding is to happen. 716 */ 717 struct GNUNET_TESTING_Command 718 GNUNET_TESTING_cmd_rewind_ip ( 719 const char *label, 720 const char *target_label, 721 unsigned int counter); 722 723 724 /* ***************** main loop logic ************* */ 725 726 /** 727 * Function called with the final result of the test. 728 * 729 * @param cls closure 730 * @param rv #GNUNET_OK if the test passed 731 */ 732 typedef void 733 (*GNUNET_TESTING_ResultCallback)( 734 void *cls, 735 enum GNUNET_GenericReturnValue rv); 736 737 738 /** 739 * Run the testsuite. Note, CMDs are copied into the interpreter state 740 * because they are _usually_ defined into the "run" method that returns after 741 * having scheduled the test interpreter. 742 * 743 * @param commands the array of command to execute 744 * @param timeout how long to wait for each command to execute 745 * @param rc function to call with the final result 746 * @param rc_cls closure for @a rc 747 * @return The interpreter. 748 */ 749 struct GNUNET_TESTING_Interpreter * 750 GNUNET_TESTING_run ( 751 const struct GNUNET_TESTING_Command *commands, 752 struct GNUNET_TIME_Relative timeout, 753 GNUNET_TESTING_ResultCallback rc, 754 void *rc_cls); 755 756 757 /** 758 * Start a GNUnet scheduler event loop and run the testsuite. Return 0 upon 759 * success. Expected to be called directly from main(). 760 * 761 * @param commands the list of command to execute 762 * @param timeout how long to wait for each command to execute 763 * @return EXIT_SUCCESS on success, EXIT_FAILURE on failure 764 */ 765 int 766 GNUNET_TESTING_main ( 767 const struct GNUNET_TESTING_Command *commands, 768 struct GNUNET_TIME_Relative timeout); 769 770 771 /* ***************** plugin logic ************* */ 772 773 774 /** 775 * The plugin API every test case plugin has to implement. 776 */ 777 struct GNUNET_TESTING_PluginFunctions; 778 779 780 struct GNUNET_TESTING_PluginFunctions * 781 GNUNET_TESTING_make_plugin ( 782 const struct GNUNET_TESTING_Command *commands); 783 784 #define GNUNET_TESTING_MAKE_PLUGIN(prefix,name,...) \ 785 void * \ 786 libgnunet_plugin_testing_ ## prefix ## _ ## name ## _init (void *cls) { \ 787 const char *my_node_id = cls; (void) my_node_id; \ 788 struct GNUNET_TESTING_Command commands[] = { \ 789 __VA_ARGS__, \ 790 GNUNET_TESTING_cmd_end () \ 791 }; \ 792 return GNUNET_TESTING_make_plugin (commands); \ 793 } \ 794 void * \ 795 libgnunet_plugin_testing_ ## prefix ## _ ## name ## _done (void *cls) { \ 796 struct GNUNET_TESTING_PluginFunctions *api = cls; \ 797 GNUNET_free (api); \ 798 return NULL; \ 799 } 800 801 802 /* *** Generic trait logic for implementing traits ********* */ 803 804 /** 805 * A `struct GNUNET_TESTING_Trait` can be used to exchange data between cmds. 806 * 807 * Therefore the cmd which like to provide data to other cmds has to implement 808 * the trait function, where an array of traits is defined with the help of 809 * the #GNUNET_TESTING_make_trait_ macro. The data can be retrieved with the 810 * help of the #GNUNET_TESTING_get_trait_ macro. Traits name and type must be 811 * defined to make use of the macros. 812 */ 813 struct GNUNET_TESTING_Trait 814 { 815 /** 816 * Index number associated with the trait. This gives the 817 * possibility to have _multiple_ traits on offer under the 818 * same name. 819 */ 820 unsigned int index; 821 822 /** 823 * Trait type, for example "reserve-pub" or "coin-priv". 824 */ 825 const char *trait_name; 826 827 /** 828 * Pointer to the piece of data to offer. 829 */ 830 const void *ptr; 831 }; 832 833 834 /** 835 * "end" of traits array. Because traits are offered into arrays, this type 836 * of trait is used to mark the end of such arrays; useful when iterating over 837 * those. 838 */ 839 struct GNUNET_TESTING_Trait 840 GNUNET_TESTING_trait_end (void); 841 842 843 /** 844 * Obtain value of a trait from a command. 845 * 846 * @param traits the array of all the traits. 847 * @param[out] ret where to store the result. 848 * @param trait type of the trait to extract. 849 * @param index index number of the trait to extract. 850 * @return #GNUNET_OK when the trait is found. 851 */ 852 enum GNUNET_GenericReturnValue 853 GNUNET_TESTING_get_trait ( 854 const struct GNUNET_TESTING_Trait *traits, 855 const void **ret, 856 const char *trait, 857 unsigned int index); 858 859 860 /** 861 * Create headers for a trait with name @a name for 862 * statically allocated data of type @a type. 863 * 864 * @param prefix symbol prefix to use 865 * @param name name of the trait 866 * @param type data type for the trait 867 */ 868 #define GNUNET_TESTING_MAKE_DECL_SIMPLE_TRAIT(prefix,name,type) \ 869 enum GNUNET_GenericReturnValue \ 870 prefix ## _get_trait_ ## name ( \ 871 const struct GNUNET_TESTING_Command *cmd, \ 872 type * *ret); \ 873 struct GNUNET_TESTING_Trait \ 874 prefix ## _make_trait_ ## name ( \ 875 type * value); 876 877 878 /** 879 * Create C implementation for a trait with name @a name for statically 880 * allocated data of type @a type. 881 * 882 * @param prefix symbol prefix to use 883 * @param name name of the trait 884 * @param type data type for the trait 885 */ 886 #define GNUNET_TESTING_MAKE_IMPL_SIMPLE_TRAIT(prefix,name,type) \ 887 enum GNUNET_GenericReturnValue \ 888 prefix ## _get_trait_ ## name ( \ 889 const struct GNUNET_TESTING_Command *cmd, \ 890 type * *ret) \ 891 { \ 892 if (NULL == cmd->traits) return GNUNET_SYSERR; \ 893 return cmd->traits (cmd->cls, \ 894 (const void **) ret, \ 895 GNUNET_S (name), \ 896 0); \ 897 } \ 898 struct GNUNET_TESTING_Trait \ 899 prefix ## _make_trait_ ## name ( \ 900 type * value) \ 901 { \ 902 struct GNUNET_TESTING_Trait ret = { \ 903 .trait_name = GNUNET_S (name), \ 904 .ptr = (const void *) value \ 905 }; \ 906 return ret; \ 907 } 908 909 910 /** 911 * Create headers for a trait with name @a name for 912 * statically allocated data of type @a type. 913 * 914 * @param prefix symbol prefix to use 915 * @param name name of the trait 916 * @param type data type for the trait 917 */ 918 #define GNUNET_TESTING_MAKE_DECL_INDEXED_TRAIT(prefix,name,type) \ 919 enum GNUNET_GenericReturnValue \ 920 prefix ## _get_trait_ ## name ( \ 921 const struct GNUNET_TESTING_Command *cmd, \ 922 unsigned int index, \ 923 type * *ret); \ 924 struct GNUNET_TESTING_Trait \ 925 prefix ## _make_trait_ ## name ( \ 926 unsigned int index, \ 927 type * value); 928 929 930 /** 931 * Create C implementation for a trait with name @a name for statically 932 * allocated data of type @a type. 933 */ 934 #define GNUNET_TESTING_MAKE_IMPL_INDEXED_TRAIT(prefix,name,type) \ 935 enum GNUNET_GenericReturnValue \ 936 prefix ## _get_trait_ ## name ( \ 937 const struct GNUNET_TESTING_Command *cmd, \ 938 unsigned int index, \ 939 type * *ret) \ 940 { \ 941 if (NULL == cmd->traits) return GNUNET_SYSERR; \ 942 return cmd->traits (cmd->cls, \ 943 (const void **) ret, \ 944 GNUNET_S (name), \ 945 index); \ 946 } \ 947 struct GNUNET_TESTING_Trait \ 948 prefix ## _make_trait_ ## name ( \ 949 unsigned int index, \ 950 type * value) \ 951 { \ 952 struct GNUNET_TESTING_Trait ret = { \ 953 .index = index, \ 954 .trait_name = GNUNET_S (name), \ 955 .ptr = (const void *) value \ 956 }; \ 957 return ret; \ 958 } 959 960 961 /** 962 * Call #op on all simple traits needed by testing core logic. 963 * 964 * @param op operation to perform 965 * @param prefix prefix to pass to @e op 966 */ 967 #define GNUNET_TESTING_SIMPLE_TRAITS(op,prefix) \ 968 op (prefix, process, struct GNUNET_OS_Process *) \ 969 op (prefix, cmd, const struct GNUNET_TESTING_Command) \ 970 op (prefix, batch_cmds, struct GNUNET_TESTING_Command *) 971 972 973 GNUNET_TESTING_SIMPLE_TRAITS (GNUNET_TESTING_MAKE_DECL_SIMPLE_TRAIT, 974 GNUNET_TESTING) 975 976 977 #endif