Introduction to Challenges involved in LoadRunner VuGen Scripting:
In this Informative LoadRunner Training Series, we explored about VuGen Script Enhancements in our previous tutorial. From our earlier tutorials until now, we have done a great progress with VuGen.
We learned how to record a script in Web HTTP/HTML protocol, how to take care of data/values with correlation and parameterization, how to ensure if the response is correct with checkpoints, how to insert transactions that measure rate and response time of user actions and other things.
With these, we should be able to successfully create scripts for almost all the web applications.
=> Click Here For Complete Series of LoadRunner Tutorials
Table of Contents:
LR language
There may be situations where we need to do more challenging tasks in a VuGen script. In this tutorial, we will discuss some of the scripting challenges along with techniques available to handle them.
Before discussing these, let’s understand a few things. VuGen (or Load Runner) can only understand its own language (let us call this as LR language, LR being the short form of Load Runner). So whatever script it generates can be said to be in LR language. In LR language, there is only one data type – String (and more precisely ‘LR String’).
Now, in order to do enhancements in a VuGen script, we generally use C language.
We know that in C language there are many data types like int, char, float, long etc. If we directly define and use C values in a request, VuGen will not understand (as it only understands ‘LR strings’) and will throw an error. So we have to convert any C value (of any data type) to ‘LR string’ before using it in a request.
Having understood this, let us go to some real-time challenging scenarios.
Scenario 1: How to use a C string in a VuGen request
Let’s assume that in a VuGen script we have a request that has a field called ‘PlanName’ (assume that this script is for some financial planning application). While recording, we entered the value as ‘NewPlan’.
web_submit_data("MyPlan", "Action={pURL}", "Method=POST", "TargetFrame=", "RecContentType=text/html", "Snapshot=t21.inf", "Mode=HTML", ITEMDATA, "Name=PlanId", "Value=67213", ENDITEM, "Name=PlanName", "Value=NewPlan", ENDITEM, "Name=Age", "Value=57", ENDITEM, "Name=MaritalStaus", "Value=Married", ENDITEM, LAST);
Say we want to use a user-defined string as the plan name.
So, we have to declare and define a string as shown below
char sPlanName[] = " MyFinancialPlan ";
The ‘sPlanName’ is a C string and hence we need to convert it into LR string (to use it in the request).
We do this using ‘lr_save_string’ function as shown below:
lr_save_string(sPlanName,”LRPlanName”);
This function assigns a value to the LR parameter/variable. It takes two attributes – The first attribute is the source (C String) and the second attribute is the destination (LR parameter/variable).
So this function saves the value of the C variable that we defined into the LR parameter ‘LRPlanName’.
Now we can substitute the ‘LRPlanName’ like any other parameter in the VuGen request.
web_submit_data("MyPlan", "Action={pURL}", "Method=POST", "TargetFrame=", "RecContentType=text/html", "Snapshot=t21.inf", "Mode=HTML", ITEMDATA, "Name=PlanId", "Value=67213", ENDITEM, "Name=PlanName", "Value={LRPlanName}", ENDITEM, "Name=Age", "Value=57", ENDITEM, "Name=MaritalStaus", "Value=Married", ENDITEM, LAST);
Note that when we run this script, all the Vusers and all the iterations will take the same value as the plan name. So in order to make the plan name unique to each run, we can do something like this.
char sPlanName[] = " MyFinancialPlan _{pVuserId}_{pIteration}"; lr_save_string( lr_eval_string(sPlanName),"LRPlanName" );
Here ‘pVuserId’ and ‘pIteration’ are the ‘Vuser ID’ and ‘Iteration Number’ parameters (that we discussed in parameter types in our previous tutorials). These are used in the plan name to ensure that we have unique names for each Vuser and iteration.
The ‘lr_eval_string’ function returns the input string after evaluating any embedded parameters. So, in this case, the output of this function will be ‘MyFinancialPlan_1_1’ for first Vuser first iteration, ‘MyFinancialPlan_1_2’ for first Vuser second iteration and so on.
And of course, we know what ‘lr_save_string’ function does.
Now we can substitute the ‘LRPlanName’ parameter as shown above.
Scenario 2: How to convert a load runner variable to C integer
In the last tutorial, we saw an example to understand how we manually pass or fail a transaction depending on a condition.
Example:
web_reg_find("Text=Welcome","SaveCount=WelcomeCount",LAST); web_submit_data("login.pl", "Action=http://127.0.0.1:1080/cgi-bin/login.pl", "Method=POST", "TargetFrame=body", "RecContentType=text/html", "Referer=http://127.0.0.1:1080/cgi-bin/nav.pl?in=home", "Snapshot=t2.inf", "Mode=HTML", ITEMDATA, "Name=userSession", "Value={corUserSession}", ENDITEM, "Name=username", "Value=jojo", ENDITEM, "Name=password", "Value=bean", ENDITEM, "Name=JSFormSubmit", "Value=off", ENDITEM, "Name=login.x", "Value=66", ENDITEM, "Name=login.y", "Value=12", ENDITEM, LAST); if(atoi(lr_eval_string("{WelcomeCount}"))>0) { lr_end_transaction("Login",LR_PASS); } else { lr_end_transaction("Login",LR_FAIL); }
We used ‘if statement’ here with ‘SaveCount’ attribute. The ‘WelcomeCount’ parameter that saves the number of occurrences of the text cannot be used directly in ‘if’ condition as it is a load runner string. So this parameter has to be converted into C string first and then to C integer. ‘lr_eval_string’ and ‘atoi’ functions are used (respectively) to take care of this.
The ‘atoi’ C function converts a C string into a C integer.
After this conversion, this can be used like any other C integer.
Scenario 3: How to send a random value in a request
Very often we come around application scenarios where we have to select a random value (say from a drop down). How do we handle this in VuGen scripts? How do we ensure that random value is selected for every iteration? Let’s see this in detail.
Let us take the example of our ‘Web Tours’ application. As we saw earlier, we have a ‘Find Flight’ page where we have to select a flight.
Say we select the first one in the list. The corresponding request in the script is like this (where the corresponding value for the flight selected).
web_submit_data("reservations.pl_2", "Action=http://127.0.0.1:1080/cgi-bin/reservations.pl", "Method=POST", "TargetFrame=", "RecContentType=text/html", "Referer=http://127.0.0.1:1080/cgi-bin/reservations.pl", "Snapshot=t5.inf", "Mode=HTML", ITEMDATA, "Name=outboundFlight", "Value= 020;338;04/03/2018", ENDITEM, "Name=numPassengers", "Value=1", ENDITEM, "Name=advanceDiscount", "Value=0", ENDITEM, "Name=seatType", "Value=Coach", ENDITEM, "Name=seatPref", "Value=None", ENDITEM, "Name=reserveFlights.x", "Value=39", ENDITEM, "Name=reserveFlights.y", "Value=10", ENDITEM, LAST);
We have to first capture the corresponding values for all the four flights from one of the previous responses. We can do this using correlation function (web_reg_save_param) with ‘ORD=ALL’ attribute before the request whose response has these value.
The output of this will be like this where the correlated parameter ‘cFlight’ has an array of four values corresponding to the four flights.
The next step would be to randomly select one of these values and submit in the request. This can be done using ‘lr_paramarr_random’ function as shown below.
strcpy(flightVal,lr_eval_string(lr_paramarr_random("cFlight")));
The input to ‘lr_paramarr_random’ function is a parameter array and the output is a random value from this array. So here the output of this function is one of the four flight values. And as this random value is an LR string, ‘lr_eval_string’ function is used (to convert the same into C string).
‘strcpy’ C function finally copies this value into a C string variable ‘flightVal’.
Now again we have to convert this C String variable into LR string to be able to send in the request.
lr_save_string(flightVal,"randomFlight"); web_submit_data("reservations.pl_2", "Action=http://127.0.0.1:1080/cgi-bin/reservations.pl", "Method=POST", "TargetFrame=", "RecContentType=text/html", "Referer=http://127.0.0.1:1080/cgi-bin/reservations.pl", "Snapshot=t5.inf", "Mode=HTML", ITEMDATA, "Name=outboundFlight", "Value={randomFlight}", ENDITEM, "Name=numPassengers", "Value=1", ENDITEM, "Name=advanceDiscount", "Value=0", ENDITEM, "Name=seatType", "Value=Coach", ENDITEM, "Name=seatPref", "Value=None", ENDITEM, "Name=reserveFlights.x", "Value=39", ENDITEM, "Name=reserveFlights.y", "Value=10", ENDITEM, LAST);
Scenario 4: How to split a string into tokens
Say there is a scenario where we have to split a string into pieces /tokens. Let’s take the example from our ‘Web Tours’ application where from the flight value 020;338;04/03/2018 say we have to use only ‘338’, then we need to split this string and store this into a variable.
To do this ‘strtok’ function is used.
’strtok’ C function returns a token from a string delimited by specified characters. After the first invocation, we have to pass ‘NULL’ as the value of the string to get the next token. The example below shows how this function is used to split the flight value based on the semicolon (;) delimiter.
Example:
Let’s assume that the flight value is captured from the relevant response into the parameter ‘cFlight’.
char string[100]; char *token; int i=1; strcpy(string,lr_eval_string("{cFlight}")); token=(char *)strtok(string,";"); lr_output_message("Token %d is %s",i,token); while(token != NULL) { i=i+1; token=(char *)strtok(NULL,";"); lr_output_message("Token %d is %s",i,token); }
The output of this can be seen in the replay log.
We can copy the required token into a parameter and use it.
Scenario 5: How to read data from and write data into a text file
Sometimes it may be required to read data from an external file or write data to an external file. Let’s see how we do this in a VuGen script.
Let’s first see how to read data from a text file.
Example: Say we have to read an XML from an external data file and use it as a request in the script.
To do this, we use ‘fread’ C function.
This function takes four attributes:
buffer – The buffer in which to store the data stream.
size – The size of the buffer.
count – The number of bytes to read.
file_pointer – The file pointer
Example code (with comments) for the same
char buffer[1000]; //The buffer to store the read data stream char *filename = "C:\\Temp\\mysamplefile.txt"; /* name and path of the file to be read from */ char * accessmode = "r"; /* access mode r /r+ = open for reading , w /w+ = open for writing ,a /a+ = open for appending */ /* "+" sign indicates that the file must already exist */ long filepointer; /* declaring a file pointer */ int count=500; /* number of bytes to be read */ filepointer = fopen(filename, accessmode); /* open file in read mode */ fread (buffer,sizeof(char),count,filepointer); /* read from output file */ lr_save_string(buffer,"requestbody"); //we can use this as a LR parmeter and can use in the script now fclose(filepointer); //close the file pointer
Note that in the code shown above, we read 500 bytes from the text file. Obviously, we may not know the file size always. So we can use ‘fseek’ and ‘ftell’ C functions (I will leave this for you to explore) to find the size of the file and use the ‘count’ attribute of the ‘fread’ function accordingly.
Now let’s see how to write data to a text file.
Example: Say we have a script which creates orders and generates ‘orderid’. If we want to know all the order ids created by our script in a test, we can make our script copy these order ids to an external text file.
‘fprintf’ – C function writes formatted output to a file.
This function takes these attributes:
file_pointer – The file pointer
format_string – The formatted string to write to the file.
args – One or more optional print arguments.
The example code is shown below. Let’s assume we have correlated and saved ‘orderid’ into the parameter ‘cOrderId’.
Example:
char *filename = "C:\\Temp\\mysamplefile.txt"; /* name and path of the file to be created or edited */ char * accessmode = "a+"; /* access mode r /r+ = open for reading , w /w+ = open for writing ,a /a+ = open for appending */ /* "+" sign indicates that the file must already exist */ long filepointer; /* declaring a file pointer */ filepointer = fopen(filename, accessmode); /* open file in append mode */ fprintf (filepointer, "%s\n", lr_eval_string("{cOrderId}")); /* write orders id to output file */ fclose(filepointer); /* close the file pointer */
Hope, we are now good with the concepts of reading data from or writing data to an external file (of course there could be the other ways of doing the same thing than what we discussed above). It would be very useful to do a thorough study on file operations in C (you can refer to any good C tutorials or books) as these are very much required in many real-time scenarios.
Scenario 6: How to handle correlation when boundaries are changing
In Correlations tutorial, we used boundary based correlation function(s) to capture the dynamic values from the response. But, what if we have a scenario where the boundaries are changing? There are several ways of handling such situations. Let’ see these in detail.
a) Using ‘IC’, ‘DIG’ and ‘ALNUM’ flags:
IC – This flag instructs VuGen to ignore case in the Left/Right boundary.
Example: If the Left Boundary is sometimes in upper case and sometimes in lower case, we use this flag.
web_reg_save_param ("corUserSession","LB/IC= name=\"userSession\" value=\"","RB=\"/>", LAST);
DIG – This flag instructs VuGen to consider any single number where the wild character ‘#’ is used in the Left/Right boundary.
Example: If the Left boundary (or the Right boundary) is changing like this (only one number at a particular position).
GJHi3rty
1GJHi8rty
GJHi7rty
We can use ‘DIG’ flag as shown below as that will take care of the changing number.
LB/DIG= GJHi#rty
ALNUM – This flag instructs VuGen to consider any single alphanumeric character where the wild character ‘^’ is used in the Left/Right boundary.
Example: If the Left boundary (or the Right boundary) is changing like this (only one alphanumeric character at a particular position).
GJHi3rty
GJHiKrty
GJHitrty
We can use ‘ALNUM’ flag as shown below as that will take care of the changing alphanumeric character
LB/ALNUM= GJHi^rty
Also, we can use two flags together – like ‘ALNUMIC’ which is both ‘ALNUM’ and ‘IC’.
b) Using ‘SaveLen’ and ‘SaveOffset’ attributes:
We can use these two attributes of the ‘web_reg_save_param’ function appropriately to input only the static portion of the Left/Right boundaries.
c) Using regular expressions:
We can use ‘web_reg_save_param_regexp’ correlation function to save the dynamic value (into a parameter) that matches a regular expression.
Example: Let’s say the dynamic value we want to capture is ‘3959339’ from the given text,
PriceControl_ctl01 “Name=jack”, “Refid=3959339” balance
We cannot use boundary based correlation function here because the value and length of the field like ‘Name’ above may change (and so we cannot use it in the left or right boundary).
We can use the ‘web_reg_save_param_regexp’ correlation function as shown below to take care of this problem.
web_reg_save_param_regexp("ParamName=corName", "RegExp= PriceControl_ctl01 \"Name=([a-z]+)\", \"Refid=([0-9]+)\" balance", "Group=1","Ordinal=All", LAST);
The regular expression groups are put in parentheses and the ‘Group’ attribute decides which group to consider for saving the corresponding match to the parameter specified (in the first attribute).
A few regular expression matching are shown below:
\d – matches a single digit
\w – matches a single word
[A-Z]+ – matches any word in upper case
[a-z]+ – matches any word in lower case
[0-9]+ – matches any numeric value
Scenario 7: How to write and use a function in a VuGen script
Like in any other programming language, we can write/define a function manually (usually called user-defined function) and use it anywhere in the VuGen script.
Let us assume that we have to send a unique plan name in every request of a particular script. So instead of writing the required code (that generates a unique name) multiple times, we can define a function (that generates a unique name) and call in whenever (and wherever) it is required in the VuGen script.
Although function in a VuGen script can be written inside any action, it is generally written inside the ‘globals.h’ file (under the Extra Files section of the VuGen script) or inside a newly created file (under the same ‘Extra Files’ section). Once written, the function can be called from any Action(s).
The image below shows a user-defined function ‘MyFunction’ written inside the ‘globals.h’ file.
As discussed above, the other way is to create a new file and write the function inside it.
The only thing to remember when creating a new file is that we have to include it in the ‘globals.h’ file (without which VuGen will not recognize this file).
Conclusion
Thus in this tutorial, we saw how to handle some real-time challenges in VuGen scripting and we would obviously come across many other scenarios when we work on various applications.
Also, you would have realized that C string functions and C file operations are very much required (and useful) in handling various scenarios. However, I would recommend you to spend some time mastering these.
In our next tutorial, we will see and understand some important pre-defined functions that are used in VuGen scripts (we have seen some of the functions already).
=> Visit Here For Complete Series of LoadRunner Tutorials