Y-lib
Loadrunner libraries
y_transaction.c
Go to the documentation of this file.
1 /*
2  * Ylib Loadrunner function library.
3  * Copyright (C) 2005-2014 Floris Kraak <randakar@gmail.com> | <fkraak@ymor.nl>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but 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 License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #ifndef _Y_TRANSACTION_C_
21 #define _Y_TRANSACTION_C_
23 
25 
88 // Needed to compile this - the definition of LAST is missing if it's not included.
89 #include "web_api.h"
90 
91 // More C definitions
92 #include "vugen.h"
93 
94 // Other Ylib functions
95 #include "y_logging.c"
96 #include "y_string.c"
97 #include "y_loadrunner_utils.c"
98 
99 
100 // Variables //
101 
102 
103 // Never access these variables directly - names may change.
104 // Use the get() and set() functions instead, if available. (otherwise, add them?)
109 
114 
117 
118 
120 #define Y_TRANS_STATUS_NONE 0
121 #define Y_TRANS_STATUS_STARTED 1
123 #define Y_TRANS_STATUS_AUTO_STARTED 2
127 
129 typedef int (y_trigger_func)();
138 
140 typedef int (y_trans_start_impl_func)(char* trans_name);
142 typedef int (y_trans_end_impl_func)(char* trans_name, int status);
147 
148 
149 
150 // Functions
151 
160 {
161  lr_start_transaction("y_workaround_transaction_to_prevent_null_dereference");
162  lr_end_transaction( "y_workaround_transaction_to_prevent_null_dereference", LR_AUTO);
163 }
164 
165 
166 // Getters / Setters //
174 {
175  return lr_eval_string("{y_current_transaction}");
176 }
177 
183 void y_set_current_transaction_name(char *trans_name)
184 {
185  lr_save_string(lr_eval_string(trans_name), "y_current_transaction");
186 }
187 
188 
196 {
197  return lr_eval_string("{y_current_sub_transaction}");
198 }
199 
200 
207 {
208  lr_save_string(lr_eval_string(trans_name), "y_current_sub_transaction");
209 }
210 
211 
220 void y_set_add_group_to_transaction(int add_group_to_trans)
221 {
222  _y_add_group_to_trans = add_group_to_trans;
223 }
224 
226 // Complain loudly at compile time if somebody tries to use the old versions of these calls
227 #define y_set_action_prefix 0_y_set_action_prefix_no_longer_exists_please_use_action_prefix
228 #define y_get_action_prefix 0_y_get_action_prefix_no_longer_exists_please_use_y_get_transaction_prefix
229 
238 void y_set_transaction_prefix(char *transaction_prefix)
239 {
240  // Bother. Let's do this the eminently simple and predictable way, then:
241  lr_save_string(transaction_prefix, "y_transaction_prefix");
242 }
243 
254 {
255  // Bother. Let's do this the eminently simple and predictable way, then:
256  if(y_is_empty_parameter("y_transaction_prefix"))
257  {
259  return "";
260  }
261  else
262  return lr_eval_string("{y_transaction_prefix}");
263 }
264 
273 {
274  return _y_transaction_nr;
275 }
276 
285 {
286  return _y_transaction_nr++;
287 }
288 
297 {
298  return _y_transaction_nr++;
299 }
300 
301 
302 void y_set_next_transaction_nr(int trans_nr)
303 {
304  _y_transaction_nr = trans_nr;
305 }
306 
307 
309 {
310  return _y_sub_transaction_nr;
311 }
312 
313 
315 {
316  return _y_sub_transaction_nr++;
317 }
318 
320 {
321  return _y_sub_transaction_nr++;
322 }
323 
325 {
326  _y_sub_transaction_nr = trans_nr;
327 }
328 
329 // Complain loudly with a compiler error if people still use the old variants of the above.
330 // We renamed these on purpose, the semantics of these functions are subtly different from the old ones so existing scripts need to change.
331 // The most important change is that the internal transaction number now represents the *next* transaction number, not the previous one.
332 #define y_set_transaction_nr 0y_set_transaction_nr_no_longer_exists_please_use_y_set_next_transaction_nr
333 #define y_get_transaction_nr 0y_get_transaction_nr_no_longer_exists_please_use_y_get_next_transaction_nr
334 #define y_get_and_increment_transaction_nr 0y_get_and_increment_transaction_nr_no_longer_exists_please_use_y_increment_transaction_nr
335 #define y_get_sub_transaction_nr 0y_get_sub_transaction_nr_no_longer_exists_please_use_y_get_next_sub_transaction_nr
336 #define y_get_and_increment_sub_transaction_nr 0y_get_and_increment_sub_transaction_nr_no_longer_exists_please_use_y_increment_sub_transaction_nr
337 #define y_set_sub_transaction_nr 0y_set_sub_transaction_nr_no_longer_exists_please_use_y_set_next_sub_transaction_nr
338 
339 
341 {
342  return _y_trans_status;
343 }
344 
345 
346 /******
347 //
348 //Users can now set trigger functions for the start and end of y_ transactions.
349 //These triggers will run just before the transaction measurements start, and
350 //just before the transaction measurements end.
351 //
352 //Usage:
353 //Define a new function, as follows:
354 //
355 //int register_save_params_trigger()
356 //{
357 // web_reg_save_param("something", ...);
358 // web_reg_save_param("same thing in a slightly different layout", ...);
359 //
360 // return LR_PASS; // this is ignored for transaction start triggers
361 //}
362 //
363 //Then, at the point where this trigger should start firing call:
364 //
365 //y_set_transaction_start_trigger( &register_save_params_trigger );
366 //
367 //From then on out every call to y_start_transaction() and
368 //y_start_sub_transaction() will fire the trigger.
369 //A call to y_run_transaction_start_trigger() will fire the trigger too.
370 //
371 //To stop the trigger from firing call 'y_set_transaction_start_trigger(NULL);'
372 //
373 //Transaction end triggers are mirror images of transaction start triggers,
374 //with the notable exception that the return value is not ignored, but
375 //used to set the end status of the transaction before it ends.
376 //
377 *****/
378 
380 {
381  _y_trigger_start_trans = trigger_function;
382 }
383 
385 {
386  _y_trigger_end_trans = trigger_function;
387 }
388 
390 {
391  _y_trigger_start_sub_trans = trigger_function;
392 }
393 
395 {
396  _y_trigger_end_sub_trans = trigger_function;
397 }
398 
399 
400 
401 // Transaction implementation change support
402 // For those people who for some reason feel compelled to implement lr_start_transaction() and lr_end_transaction themselves :p
403 
404 // Definitions can be found further up. For reference:
405 // y_trans_start_impl_func* _y_trans_start_impl = &lr_start_transaction;
406 // y_trans_end_impl_func* _y_trans_end_impl = &lr_end_transaction;
407 //
409 {
410  _y_trans_start_impl = trans_start_func;
411 }
412 
414 {
415  _y_trans_end_impl = trans_end_func;
416 }
417 
419 {
420  return _y_trans_start_impl;
421 }
422 
424 {
425  return _y_trans_end_impl;
426 }
427 
428 
429 // End getters/setters
430 
431 
432 
434 {
435  if( _y_trigger_start_trans == NULL )
436  {
437  return 0;
438  }
439  else return _y_trigger_start_trans();
440 }
441 
443 {
444  if( _y_trigger_end_trans == NULL )
445  {
446  return 0;
447  }
448  else return _y_trigger_end_trans();
449 }
450 
452 {
453  if( _y_trigger_start_sub_trans == NULL )
454  {
455  return 0;
456  }
457  else return _y_trigger_start_sub_trans();
458 }
459 
461 {
462  if( _y_trigger_end_sub_trans == NULL )
463  {
464  return 0;
465  }
466  else return _y_trigger_end_sub_trans();
467 }
468 
469 
470 //
471 // Helper function to save the transaction end status before y_end_(sub_)transaction() closes them.
472 //
473 void y_save_transaction_end_status(char* transaction_name, const char* saveparam, int status)
474 {
475  int actual_status = lr_get_transaction_status(transaction_name);
476 
477  if( actual_status == LR_PASS )
478  {
479  // LR thinks everything is fine. If our code doesn't that becomes the new end status.
480  lr_set_transaction_status(status);
481  }
482  else // in case of a LR reported fail status of some kind.
483  {
484  // The loadrunner reported status takes precendence as those errors are usually quite fundamental.
485  status = actual_status;
486  }
487 
488  if( actual_status == -16863 )
489  {
490  // Fix me: Lookup the corresponding LR constant.
491  lr_log_message("Warning: Possible attempt to close a transaction that has not been opened!");
492  }
493  lr_save_int(status, saveparam);
494 }
495 
496 
497 
498 
500 
501 
502 
504 {
506 }
507 
508 void y_session_transaction_count_report(char* session_name)
509 {
510  lr_log_message( lr_eval_string("Transaction count for %s: %d"), session_name, y_session_transaction_count);
511  lr_user_data_point( session_name, y_session_transaction_count);
512 }
513 
515 {
517 }
518 
519 
520 
521 //
522 // Transaction blocks. Prefix all transactions in a series with the same text.
523 //
524 
525 void y_start_transaction_block(char *transaction_prefix)
526 {
527  lr_log_message("Starting transaction block %s", transaction_prefix);
528  y_set_transaction_prefix(transaction_prefix);
530 
531  // Start a transaction to measure total time spend in this block
532  //
533  //snprintf(_block_transaction, strlen(transaction_prefix)+7, "%s_TOTAL", transaction_prefix);
534  //lr_start_transaction(_block_transaction);
535 }
536 
538 {
539  lr_log_message("Ending transaction block %s", y_get_transaction_prefix());
541 }
542 
543 
545 {
546  lr_log_message("Pausing transaction block %s", y_get_transaction_prefix());
547  if( y_is_empty_parameter("y_transaction_prefix") )
548  {
549  lr_error_message("Attempt to pause transaction block when none has been started!");
550  return;
551  }
552  lr_save_int( y_get_next_transaction_nr(), lr_eval_string("y_paused_transaction_block_{y_transaction_prefix}_trans_nr") );
554 }
555 
556 
557 void y_resume_transaction_block(char *transaction_prefix)
558 {
559  char *storage_param;
560  lr_log_message("Resuming transaction block %s", transaction_prefix);
561 
562  lr_save_string(transaction_prefix, "y_resumed_transaction_block");
563  storage_param = lr_eval_string("y_paused_transaction_block_{y_resumed_transaction_block}_trans_nr");
564 
565  if( y_is_empty_parameter(storage_param) )
566  {
567  lr_error_message("Attempt to resume transaction block %s but no such block has been paused.", transaction_prefix);
568  return;
569  }
570 
571  y_start_transaction_block(transaction_prefix);
573 }
574 
575 
576 // DEPRECATED
577 void y_start_action_block(char *transaction_prefix)
578 {
579  y_start_transaction_block(transaction_prefix);
580 }
581 
582 
583 // DEPRECATED
585 {
587 }
588 
589 
591 // Complain loudly at compile time if somebody tries to use the old versions of this call
592 #define y_calculate_actual_action_prefix 0_y_calculate_actual_action_prefix_no_longer_exists_please_use_y_calculate_actual_transaction_prefix
593 
595 
608 char *y_calculate_actual_transaction_prefix(const char *transaction_prefix)
609 {
610  const char seperator[] = "_";
611  const int seperator_len = sizeof seperator - 1; // strlen(seperator);
612  int group_len = 0;
613  int prefix_len = strlen(transaction_prefix);
614  char *buffer;
615  size_t buffer_size;
616 
617  // y_virtual_user_group is set only if y_setup() is called.
618  // See y_loadrunner_utils.c
619  y_setup();
621  {
622  group_len = strlen(y_virtual_user_group);
623  }
624 
625  // add room for the seperators
626  if(prefix_len > 0)
627  {
628  prefix_len += seperator_len;
629  }
630  if(group_len > 0)
631  {
632  group_len += seperator_len;
633  }
634 
635  // allocate memory -- note this needs to be free()'ed afterwards!
636  buffer_size = group_len + prefix_len + 1;
637  buffer = y_mem_alloc(buffer_size);
638  buffer[0] = '\0';
639 
640  // start concatenating things together
641  {
642  int len = 0;
643  if(group_len > 0)
644  {
645  len = snprintf(buffer, buffer_size, "%s%s", y_virtual_user_group, seperator);
646  }
647  if(prefix_len > 0)
648  {
649  snprintf(buffer + len, buffer_size-len,"%s%s", transaction_prefix, seperator);
650  }
651  }
652  return buffer;
653 }
654 
655 
656 //
657 // Generates the transaction name prefixed with a user defined action prefix and a transaction number.
658 // The result is saved in the "y_current_transaction" loadrunner parameter for use by some macro's.
659 //
660 // To use this scripts need to call y_start_action_block() - once at the start of each action.
661 //
662 //
663 // Dirty trick that no longer needs to be used:
664 //#define lr_start_transaction(transaction_name) y_start_new_transaction_name(transaction_name, _y_transaction_prefix, _trans_nr++); \
665 // lr_start_transaction(lr_eval_string("{y_current_transaction}"))
666 //#define lr_end_transaction(transaction_name, status) lr_end_transaction(lr_eval_string("{y_current_transaction}"), status)
667 //
668 void y_create_new_transaction_name(const char *transaction_name, const char *transaction_prefix, int transaction_nr)
669 {
670  const int trans_nr_len = 2; // eg. '01'
671  char *actual_prefix = y_calculate_actual_transaction_prefix(transaction_prefix);
672  int prefix_len = strlen(actual_prefix);
673  int trans_name_size = prefix_len + trans_nr_len +1 + strlen(transaction_name) +1;
674  char *actual_trans_name = y_mem_alloc( trans_name_size );
675 
676  if( transaction_nr >= 100 )
677  {
678  y_log_error("Transaction count too high (100+). Are you using y_start_action_block()?");
679  lr_exit(LR_EXIT_VUSER, LR_FAIL);
680  }
681 
682  snprintf(actual_trans_name, trans_name_size, "%s%02d_%s", actual_prefix, transaction_nr, transaction_name);
683  free(actual_prefix);
684  y_set_current_transaction_name(actual_trans_name);
685  free(actual_trans_name);
686 }
687 
688 void y_create_next_transaction_name( const char* transaction_name)
689 {
691 }
692 
693 
694 
695 //
696 // Todo: Find a way to make this share more code with y_create_new_transaction_name()
697 //
698 void y_create_new_sub_transaction_name(const char *transaction_name, const char *transaction_prefix,
699  const int transaction_nr, const int sub_transaction_nr)
700 {
701  const int trans_nr_len = 2; // eg. '01'
702  char *actual_prefix = y_calculate_actual_transaction_prefix(transaction_prefix);
703  int prefix_len = strlen(actual_prefix);
704  int trans_name_size = prefix_len + (2 * (trans_nr_len +1)) + strlen(transaction_name) +1;
705  char *actual_trans_name = y_mem_alloc( trans_name_size );
706 
707  if( transaction_nr >= 100 )
708  {
709  y_log_error("Transaction count too high (100+). Are you using y_start_action_block()?");
710  lr_exit(LR_EXIT_VUSER, LR_FAIL);
711  }
712 
713  snprintf(actual_trans_name, trans_name_size, "%s%02d_%02d_%s", actual_prefix, transaction_nr, sub_transaction_nr, transaction_name);
714  free(actual_prefix);
715  y_set_current_sub_transaction_name(actual_trans_name);
716  free(actual_trans_name);
717 }
718 
719 
720 void y_create_next_sub_transaction_name(const char* transaction_name)
721 {
722  y_create_new_sub_transaction_name(transaction_name,
726 }
727 
728 //
729 // y_start_transaction() / y_end_transaction()
730 // These are drop-in replacements for the loadrunner functions
731 // lr_start_transaction() and lr_end_transaction().
732 //
733 // These variants will add a bit more logging to facilitate post-test analysis
734 // with external tools, and add a common prefix based on the action block (see above)
735 // as well as consistent numbering.
736 //
737 int y_start_transaction(char *transaction_name)
738 {
739  // This saves it's result in the 'y_current_transaction' parameter.
740  y_create_next_transaction_name(transaction_name);
741 
742  // Reset the sub transaction numbering.
744 
745  // Fire the start trigger. For complicated web_reg_find() / web_reg_save_param()
746  // statement collections that we want run right before starting every
747  // transaction in a group of transactions.
748  // Placed after the generation of the transaction name since that might be
749  // a nice thing to have available.for trigger authors.
751 
752  // Stops sub transactions from automagically
753  // creating outer transactions for themselves.
755 
756  //return lr_start_transaction(lr_eval_string("{y_current_transaction}"));
757  return _y_trans_start_impl(lr_eval_string("{y_current_transaction}"));
758 }
759 
760 
761 int y_start_transaction_with_number(char *transaction_name, int transaction_number)
762 {
763  y_set_next_transaction_nr(transaction_number);
764  return y_start_transaction(transaction_name);
765 }
766 
767 
768 
769 // Note: This completely ignores the 'transaction_name' argument
770 // to retain compatibility with lr_end_transaction().
771 int y_end_transaction(char *transaction_name, int status)
772 {
773  char *trans_name = lr_eval_string("{y_current_transaction}");
774 
775  // Fire the transaction end trigger. For processing the results of
776  // complicated web_reg_find() / web_reg_save_param() statement
777  // collections that repeat for a group of transactions.
778  // This fires before the actual end of the transaction so that it can
779  // still influence the transaction end status.
780  int trigger_result = y_run_transaction_end_trigger();
781  if( status == LR_PASS && trigger_result != LR_PASS )
782  {
783  lr_error_message("Transaction end trigger did not return LR_PASS");
784  status = trigger_result;
785  }
786 
787  // Save the end status of this transaction. It won't be available after ending it.
788  y_save_transaction_end_status(trans_name, "y_last_transaction_status", status);
789 
790  // Debugging: report wasted time.
791  // People who implement their own triggers will have to do this themselves.
792  if( _y_wasted_time_graph && _y_trans_end_impl == lr_end_transaction )
793  lr_user_data_point( lr_eval_string("wasted_{y_current_transaction}"), lr_get_transaction_wasted_time(trans_name));
794 
795  // End the transaction
796  status = _y_trans_end_impl(trans_name, status);
797 
798  // Tell our subtransaction support that there is no outer transaction
799  // so if a sub-transaction is created it may have to fake this.
801 
802  if( y_session_transaction_count >= 0 ) // Values smaller than 0 means that transaction counting is disabled.
804 
805  return status;
806 }
807 
808 //
809 // y_start_sub_transaction() / y_end_sub_transaction()
810 // Like y_start_transaction() / y_end_transaction().
811 //
812 // Can be called outside of a running top level transaction,
813 // in which case it will create one as needed.
814 //
815 // This is not meant an excuse to be lazy about adding top level transactions
816 // but as a fallback for situations where the sub transactions can not neccesarily
817 // be predicted. (Think 'sudden popups from GUI apps' and similar cases.)
818 //
819 int y_start_sub_transaction(char *transaction_name)
820 {
821  // if there is no outer transaction yet, fake one
823  {
824  y_start_transaction(transaction_name);
826  }
827 
828 
829  y_create_next_sub_transaction_name(transaction_name);
830 
831  // Fire the transaction start trigger.
833 
834  // Actual sub transaction start
835  return lr_start_sub_transaction(
836  lr_eval_string("{y_current_sub_transaction}"),
837  lr_eval_string("{y_current_transaction}"));
838 }
839 
840 int y_start_sub_transaction_with_number(char *transaction_name, int transaction_number)
841 {
842  y_set_next_sub_transaction_nr(transaction_number);
843  return y_start_sub_transaction(transaction_name);
844 }
845 
846 
847 
848 int y_end_sub_transaction(char *transaction_name, int status)
849 {
850  char *trans_name = lr_eval_string("{y_current_sub_transaction}");
851 
852  // Fire the transaction end trigger.
853  int trigger_result = y_run_sub_transaction_end_trigger();
854  if( status == LR_PASS && trigger_result != LR_PASS )
855  {
856  status = trigger_result;
857  }
858 
859  // Save the end status of this transaction. It won't be available after ending it.
860  y_save_transaction_end_status(trans_name, "y_last_sub_transaction_status", status);
861 
862  // Debugging: report wasted time.
863  if( _y_wasted_time_graph )
864  lr_user_data_point( lr_eval_string("wasted_{y_current_sub_transaction}"), lr_get_transaction_wasted_time(trans_name));
865 
866  // End the transaction
867  status = lr_end_sub_transaction(trans_name, status);
868 
869  // if we faked an outer transaction, fake closing it.
870  //
871  // Note: It might be an idea to move this to y_start_(sub_)transaction() instead, for
872  // better grouping. That may not be without it's problems though.
874  {
875  y_end_transaction(transaction_name, status);
876  }
877  return status;
878 }
879 
881 {
882  char* last_trans_status_string = y_get_parameter_or_null("y_last_transaction_status");
883  if( last_trans_status_string == NULL )
884  {
885  return LR_AUTO; // No earlier transaction, the parameter doesn't even exist.
886  }
887  else
888  {
889  return atoi(last_trans_status_string);
890  }
891 }
892 
893 
894 
896 merc_timer_handle_t y_session_timer = NULL;
897 
898 
899 void y_session_timer_start(char* session_name)
900 {
901  lr_save_string(session_name, "y_session_name");
903 
904  y_session_timer = lr_start_timer();
905 }
906 
907 // Meet sessie duur en forceer een pause tot het einde van de sessie, indien nodig.
908 #define Y_NO_PAUSE 0
909 #define Y_FORCE_PAUSE 1
910 
911 
912 void y_session_timer_end(int required_session_duration, int force_pause)
913 {
914  double measured_duration;
915 
916  if( y_session_timer == NULL )
917  {
918  lr_error_message("Error: y_session_timer_end() called without matching call to y_session_timer_end()!");
919  lr_set_transaction( "__y_sesssion_timer_end_call_without_y_session_timer_end_call", 0, LR_FAIL);
920  return;
921  }
922  else
923  {
924  double measured_duration = lr_end_timer(y_session_timer);
925  // Calculate how much time remains until the session should end.
926  int remaining_time = required_session_duration - measured_duration;
927 
928  // Reset the timer insofar lr_end_timer() hasn't done that already.
929  y_session_timer = NULL;
930 
931  lr_user_data_point( lr_eval_string("y_session_duration_{y_session_name}"), measured_duration);
932  if ( remaining_time > 0 )
933  {
934  if( force_pause == Y_FORCE_PAUSE )
935  {
936  lr_force_think_time(remaining_time);
937  }
938  }
939  else
940  {
941  lr_error_message( lr_eval_string("WARNING!: Measured duration of session {y_session_name} (%f) exceeded specified maximum of %d seconds!"), measured_duration, required_session_duration);
942  lr_set_transaction( lr_eval_string("_{y_session_name}_session_duration_overrun"), measured_duration, LR_FAIL);
943  }
944  }
945 
946  y_session_transaction_count_report(lr_eval_string("y_transaction_count_{y_session_name}"));
947 }
948 
949 // Handy shortcuts //
950 
951 
952 
953 //
954 // Shorthand for
955 // "y_start_transaction(transaction); web_link(linkname); y_end_transaction(transaction)"
956 //
957 // Note: In order for the logging to report correct line numbers it is advised to use the macro
958 // version TRANS_WEB_LINK() found below.
959 //
960 // @author: Floris Kraak
961 //
962 void y_trans_web_link(char *transaction, char *linkname)
963 {
964  char *link = lr_eval_string(linkname);
965  char *tmp, *trans;
966  size_t size;
967 
968  if( !(strlen(link) > 0) )
969  {
970  lr_error_message("Zero-length link name - correlation error?");
971  lr_exit(LR_EXIT_ITERATION_AND_CONTINUE, LR_AUTO);
972  return;
973  }
974 
975  size = strlen(link) + strlen("Text=") +1;
976  tmp = y_mem_alloc(size);
977  snprintf(tmp, size, "Text=%s", link);
978 
979  trans = lr_eval_string(transaction);
980  y_start_transaction(trans);
981  web_link(link, tmp, LAST);
982  y_end_transaction(trans, LR_AUTO);
983 
984  free(tmp);
985 }
986 
987 
988 
989 //
990 // Shorthand for
991 // "y_start_transaction(transaction); web_link(linkname); y_end_transaction(transaction)"
992 // Macro version. Use this to preserve line numbers in the virtual user log.
993 // For the regular version see y_trans_web_link() above.
994 //
995 // Use as if calling a function named TRANS_WEB_LINK() with two arguments.
996 // (Being able to just search/replace y_trans_web_link( with Y_TRANS_WEB_LINK( in
997 // a vUser script is a feature, so keep the interfaces and functionality identical
998 // please.)
999 //
1000 #define Y_TRANS_WEB_LINK( TRANSACTION, LINKNAME ) \
1001 do { \
1002  char *link = lr_eval_string(LINKNAME); \
1003  char *tmp, *trans; \
1004  size_t size; \
1005  \
1006  if( !(strlen(link) > 0) ) \
1007  { \
1008  lr_error_message("Zero-length link name - correlation error?"); \
1009  lr_exit(LR_EXIT_ITERATION_AND_CONTINUE, LR_AUTO); \
1010  return; \
1011  } \
1012  \
1013  size = strlen(link) + strlen("Text=") +1; \
1014  tmp = y_mem_alloc(size); \
1015  snprintf(tmp, size, "Text=%s", link); \
1016  \
1017  trans = lr_eval_string(TRANSACTION); \
1018  y_start_transaction(trans); \
1019  web_link(link, tmp, LAST); \
1020  y_end_transaction(trans, LR_AUTO); \
1021  \
1022  free(tmp); \
1023 } while(0)
1024 
1025 
1026 //
1027 // Deprecated - The below needs to be done in some other way that doesn't
1028 // confuse the heck out of people ;-)
1029 //
1030 
1031 
1032 
1033 // Set up a series of chances that certain named steps will happen.
1034 //
1035 // The idea is that there is a .dat file listing names of steps and
1036 // for each of those the chance that that step should be executed.
1037 // The values in this .dat file are accessed 'on each occurrance' by the
1038 // "step" and "stepchance" parameters.
1039 //
1040 // This function will iterate over the step parameter until it contains "END",
1041 // and save each step chance to a seperate parameter with a name starting with
1042 // 'step_chance_'.
1043 //
1044 // Before each step is executed a call is made to y_waterfall_random_weighted_continue()
1045 // with the name of the step added. If the corresponding parameter was set up the
1046 // value it contained is used as the weighted chance that the next part of the script
1047 // will be executed.
1048 //
1049 // @author: Floris Kraak
1050 //
1052 {
1053  char *step = lr_eval_string("{step}");
1054  char *stepchance = lr_eval_string("{stepchance}");
1055  char *head = "step_chance_";
1056  char *tmp;
1057 
1058  while ( step && (strcmp(step, "END") != 0) )
1059  {
1060  size_t size = strlen(head) + strlen(step) +1;
1061  tmp = y_mem_alloc(size);
1062 
1063  snprintf(tmp, size, "%s%s", head, step);
1064 
1065  lr_save_string(stepchance, tmp);
1066  free(tmp);
1067 
1068  // We're hiding a for() loop here ;-)
1069  step = lr_eval_string("{step}");
1070  stepchance = lr_eval_string("{stepchance}");
1071  }
1072 }
1073 
1074 //
1075 // for full documentation see y_setup_step_waterfall()
1076 //
1077 // @see y_setup_step_waterfall
1078 // @author: Floris Kraak
1079 //
1081 {
1082  char *head = "step_chance_";
1083  size_t size = strlen(head) + strlen(stepname) +3;
1084  char *paramname = y_mem_alloc(size);
1085  char *chancestr;
1086  int chance = 100; // Default
1087  int rnum = (y_rand() % 100); // random number between 0 and 99
1088 
1089  lr_log_message("Weighted stop chance evaluation for %s", stepname);
1090 
1091  snprintf( paramname, size, "%s%s%s%s", "{", head, stepname, "}" );
1092  chancestr = lr_eval_string(paramname);
1093 
1094  if( (strlen(chancestr) > 0) && (strcmp(chancestr, paramname) != 0) )
1095  {
1096  chance = atoi(chancestr);
1097  }
1098  free(paramname);
1099 
1100  //lr_log_message("rnum = %d, chance = %d", rnum, chance);
1101 
1102  if( rnum >= chance )
1103  {
1104  lr_log_message("Stop!");
1105  lr_exit(LR_EXIT_ACTION_AND_CONTINUE, LR_AUTO);
1106  }
1107  else {
1108  lr_log_message("No stop!");
1109  }
1110 }
1111 
1112 
1113 #endif // _Y_TRANSACTION_C_
void y_set_transaction_prefix(char *transaction_prefix)
Y-lib string function library.
int y_run_transaction_start_trigger()
void y_setup()
Ylib setup - determines and stores the identity of the virtual user.
Definition: y_core.c:85
void y_set_current_sub_transaction_name(char *trans_name)
void y_session_timer_end(int required_session_duration, int force_pause)
y_trans_end_impl_func * _y_trans_end_impl
End transaction implementation pointer. Default lr_end_transaction().
int( y_trigger_func)()
Transaction trigger support typedef.
y_trans_start_impl_func * _y_trans_start_impl
Start transaction implementation pointer. Default lr_start_transaction().
int _y_wasted_time_graph
INTERNAL: Whether to create a graph detailing wasted time. Debugging option.
y_trigger_func * _y_trigger_start_sub_trans
Standard C function headers.
int y_start_sub_transaction_with_number(char *transaction_name, int transaction_number)
int y_end_transaction(char *transaction_name, int status)
int y_increment_transaction_nr()
void y_waterfall_random_weighted_continue(char *stepname)
char * y_calculate_actual_transaction_prefix(const char *transaction_prefix)
Transaction name factory helper.
int( y_trans_start_impl_func)(char *trans_name)
void y_set_next_transaction_nr(int trans_nr)
void y_session_transaction_count_report(char *session_name)
void y_create_new_transaction_name(const char *transaction_name, const char *transaction_prefix, int transaction_nr)
merc_timer_handle_t y_session_timer
Session timer variable for session timer support.
void y_create_new_sub_transaction_name(const char *transaction_name, const char *transaction_prefix, const int transaction_nr, const int sub_transaction_nr)
void y_save_transaction_end_status(char *transaction_name, const char *saveparam, int status)
char * y_mem_alloc(size_t size)
Ylib wrapper for malloc()
Definition: y_core.c:221
int y_start_transaction(char *transaction_name)
int y_run_sub_transaction_end_trigger()
int( y_trans_end_impl_func)(char *trans_name, int status)
int y_session_transaction_count_increment()
void y_set_add_group_to_transaction(int add_group_to_trans)
y_trans_end_impl_func * y_get_transaction_end_implementation()
void y_set_current_transaction_name(char *trans_name)
int y_post_increment_transaction_nr()
int atoi(const char *string)
Documented at http://www.cplusplus.com/reference/cstdlib/atoi/.
int strcmp(const char *string1, const char *string2)
Documented at http://www.cplusplus.com/reference/cstring/strcmp/.
void y_log_error(char *message)
Log an error message, with a timestamp, if extra logging is enabled.
Definition: y_logging.c:153
#define Y_FORCE_PAUSE
void y_resume_transaction_block(char *transaction_prefix)
y_trans_start_impl_func * y_get_transaction_start_implementation()
void y_create_next_sub_transaction_name(const char *transaction_name)
void y_set_transaction_start_implementation(y_trans_start_impl_func *trans_start_func)
void y_session_transaction_count_reset()
void y_start_action_block(char *transaction_prefix)
int _y_add_group_to_trans
INTERNAL: Whether to add the name of the vuser group to the transaction names. 1 = on...
void __y_do_not_call_this_is_a_workaround_that_only_exists_to_prevent_a_null_dereference_error_in_vugen_when_running()
Workaround for a bug in LR 11.
int y_get_next_transaction_nr()
char * y_get_transaction_prefix()
int y_get_next_sub_transaction_nr()
#define Y_TRANS_STATUS_NONE
Transaction status tracking.
int y_end_sub_transaction(char *transaction_name, int status)
int _y_transaction_nr
INTERNAL: Transaction counting for transaction blocks:
void y_session_timer_start(char *session_name)
void y_start_transaction_block(char *transaction_prefix)
void y_trans_web_link(char *transaction, char *linkname)
char * y_get_current_sub_transaction_name()
int y_run_sub_transaction_start_trigger()
void y_set_sub_transaction_start_trigger(y_trigger_func *trigger_function)
void y_set_transaction_end_implementation(y_trans_end_impl_func *trans_end_func)
void y_set_next_sub_transaction_nr(int trans_nr)
void y_end_action_block()
size_t strlen(const char *string)
Documented at http://www.cplusplus.com/reference/cstring/strlen/.
int y_is_empty_parameter(const char *param_name)
Test if the given parameter is empty or not yet set. (These are two different things..) It would be nice if loadrunner had a builtin for this.
Definition: y_core.c:305
Collection of miscellaneous support functions.
void y_set_sub_transaction_end_trigger(y_trigger_func *trigger_function)
int y_post_increment_sub_transaction_nr()
Logging-related y-lib functions.
char * y_get_current_transaction_name()
y_trigger_func * _y_trigger_end_sub_trans
int _y_sub_transaction_nr
INTERNAL: Transaction counting for sub transactions:
void y_set_transaction_start_trigger(y_trigger_func *trigger_function)
void y_setup_step_waterfall()
int snprintf(char *buffer, size_t n, const char *format_string,...)
Documented at http://www.cplusplus.com/reference/cstdio/snprintf/. This function was introduced by t...
int _y_trans_status
INTERNAL: Transaction status tracking.
long y_rand(void)
Generate a random (integer) number between 0 and Y_RAND_MAX (30 bit maxint).
Definition: y_core.c:156
char * y_virtual_user_group
The virtual user group, as reported by lr_whoami().
Definition: y_core.c:42
char * y_get_parameter(const char *param_name)
Get the content of a parameter and return it as a char *.
Definition: y_core.c:336
void y_set_transaction_end_trigger(y_trigger_func *trigger_function)
y_trigger_func * _y_trigger_start_trans
#define Y_TRANS_STATUS_AUTO_STARTED
Transaction status tracking.
char * y_get_parameter_or_null(const char *param_name)
Get the content of a parameter and return it as a char *, or return NULL if it wasn&#39;t set...
Definition: y_core.c:373
int y_get_transaction_running()
int y_start_transaction_with_number(char *transaction_name, int transaction_number)
#define Y_TRANS_STATUS_STARTED
Transaction status tracking.
void y_create_next_transaction_name(const char *transaction_name)
void y_pause_transaction_block()
void y_end_transaction_block()
int y_run_transaction_end_trigger()
y_trigger_func * _y_trigger_end_trans
int y_increment_sub_transaction_nr()
void free(void *mem_address)
Documented at http://www.cplusplus.com/reference/cstdlib/free/.
int y_get_last_transaction_status()
int y_session_transaction_count
Transaction counting support for sessions.
int y_start_sub_transaction(char *transaction_name)