Occasionally you will find that you must write some code in VuGen to continuously check that the system has completed something, before you continue.

Two examples that I have found recently were:

  • A web application that generates reports. Click a button to generate a report. The report gets generated in the background on the report server. When the report is ready to be viewed, the web page will be updated with the report name appearing as a hyperlink. The virtual user should keep refreshing the page until the report is available, then they should view the report. Typically report generation takes 10 minutes.
  • A message-based system. An order message is placed on a queue, where it is picked up and processed by the system. Processing typically takes 30-90 seconds, and is complete when the status of the order is flagged as “complete” in the database. To determine the processing time for the order, the virtual user must repeadedly query the database using the order number. Once the order status is “complete”, a transaction can be created with the correct duration (using lr_set_transaction).

If you have a basic understanding of your chosen VuGen user type, and know how to write the code for a loop, you might think that writing code to do this is easy.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// Code taken from HP whitepaper on LoadRunner by 
// Opral Wisham from Waste Management, Inc.
 
// This example was used in a script that required clicking
// the "refresh" button until the run status changed to
// "success". This code provides an automatic refresh
// until the batch job has been completed. The next step
// requires the completion of the batch job.
 
int x; // flag will be 0 or 9
char *temp, *temp2; // values to hold strings
 
Action()
{
  temp2="Success"; //compare string 2
  //lr_message("temp2 = %s", temp2);
 
  // set x to 0. x is the success flag
  x=0;
 
  do {
    web_reg_save_param("RunStatus",
      "LB=<td align=’LEFT’ class=’PSLEVEL1GRIDODDROW’>\n",
      "RB=\n",
      "Ord=5",
      "Search=body",
      LAST);
 
    web_submit_data("PROCESSMONITOR.PROCESSMONITOR.GBL",
      "Action=http://crpu028a:8050/psc/fs84cpv/EMPLOYEE/ERP/c/PROCESSMONITOR.PROCESSMONITOR.GBL",
      "Method=POST",
      "RecContentType=text/html",
      "Referer=http://crpu028a:8050/psc/fs84cpv/EMPLOYEE/ERP/c/PROCESSMONITOR.PROCESSMONITOR.GBL?Page=PMN_PRCSLIST&Action=U&",
      "Snapshot=t17.inf",
      "Mode=NORESOURCE",
      ITEMDATA,
      "Name=ICType", "Value=Panel", ENDITEM,
      "Name=ICElementNum", "Value=0", ENDITEM,
      "Name=ICStateNum", "Value={ICStateNum6}", ENDITEM,
      "Name=ICAction", "Value=REFRESH_BTN", ENDITEM,
      "Name=ICXPos", "Value=0", ENDITEM,
      "Name=ICYPos", "Value=0", ENDITEM,
      "Name=ICFocus", "Value=", ENDITEM,
      "Name=ICChanged", "Value=-1", ENDITEM,
      "Name=ICFind", "Value=", ENDITEM,
      "Name=PMN_FILTER_WS_OPRID", "Value=CPVID", ENDITEM,
      "Name=PMN_FILTER_PRCSTYPE", "Value=", ENDITEM,
      "Name=PMN_FILTER_FILTERVALUE", "Value=1", ENDITEM,
      "Name=PMN_FILTER_FILTERUNIT", "Value=1", ENDITEM,
      "Name=PMN_FILTER_SERVERNAME", "Value=PSUNX", ENDITEM,
      "Name=PMN_FILTER_PRCSNAME", "Value=", ENDITEM,
      "Name=PMN_DERIVED_PRCSINSTANCE", "Value={Process_Instance}", ENDITEM,
      "Name=PMN_DERIVED_TO_PRCSINSTANCE", "Value={Process_Instance}", ENDITEM,
      "Name=PMN_FILTER_RUNSTATUS", "Value=", ENDITEM, 
      LAST);
 
    // Compare correlation value with character string
    temp = lr_eval_string(lr_eval_string("{RunStatus}"));
    // correlation value to variable
    //lr_message("temp = %s", temp);
    //compare string 1
    if(strcmp(temp,temp2)==0){
      // string compare success with correlation value
      x=9; // set flag to indicate success
    }
  } while (x == 0); // do while flag not set
 
  return 0;
}

The example code above has two major problems:

  • the polling loop will run forever if it never finds the string “success” on the page it is checking
  • the VuGen script will refresh the page it is checking as fast as possible. This means that your virtual user is not behaving like a real user at all. This behaviour may create hundreds or thousands of additional requests on the system. Potentially it may keep an entire CPU core busy on the system being monitored or tested (and it will also put unnecessary load on your load generators).

So, whether your script is for performance testing with LoadRunner or for application monitoring with BAC, it is important that your polling loop has some think-time inside it so that it does not hit the server too hard, and that it will exit after a reasonable period of time if the event being polled for has not happened.

Here is a better implementation of a polling loop.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  int POLLING_TIMEOUT = 600; // 10 minutes
  long start_time;
 
  // Will keep refreshing the report page until it finds "Success" or reaches POLLING_TIMEOUT.
  time(&start_time);
  do {
 
    lr_think_time(2);
 
    web_reg_find("Text=Success",
      "Search=Body",
      "SaveCount=SuccessCount",
      LAST);
 
    web_submit_data("Display Report",
      "Action=http://www.example.com/reporting/display.do",
      "Method=POST",
      "RecContentType=text/html",
      "Referer=http://www.example.com/reporting/",
      "Snapshot=t1.inf",
      "Mode=HTML",
      ITEMDATA,
      "Name=report_id", "Value={ReportID}", ENDITEM,
      "Name=report_filter", "Value=", ENDITEM, 
      LAST);
 
	// Abort script if POLLING_TIMEOUT is exceeded.
    if ( (time(NULL) - start_time) > POLLING_TIMEOUT) {
		lr_error_message("Timed out while waiting for report to generate.");
		lr_abort();
	}
 
  } while (atoi(lr_eval_string("{SuccessCount}")) == 0);

4 comments on “The “is it done yet” loop

  1. A best practise for Vugen scripting is to compile a library of scripts for patterns of reuse in a standard LR implementation. Frameworks of designed scripts can be created for specific situations. LR for SAP protocol, LR for cross browser mobile applications, Citrix protocol etc.

  2. Hey,

    Did you happen to try the Async feature in LoadRunner 11.50?
    The web_reg_async_attributes step allows registering a download to be performed repeatedly in set intervals (Polling).
    The polling is performed asynchronously to the rest of the script (including lr_think_time steps or other downloads).

    Oded Keret
    LoadRunner R&D
    HP Software

  3. lr_think_time()? What if this script is run with think time turned off? Or just limited. How about sleep()? Same result as think_time but always gets executed and you are not exposed to the risk of someone changing the run time settings and this screwing the logic. plus it allows you to debug the script much easier.

    It’s a bit of a hammer, the sleep function, and it can cause issues when stopping the scenario (when the script is asleep is is the sleep of the dead, it will not respond to external requests) but nothing a bit of patience won’t fix.

Leave a Reply