Wednesday, February 8, 2017

Debugging a LoadRunner script

Each performance engineer has his own style of debugging and is comfortable one of the approaches. While the following approach doesn’t claim to be the best approach, it sure helps with an approach for the beginners and act as a quick reference for the hands on guys as well.

·         One request at a time - While some go with one concept at a time, this approach suggests to go with one request / transaction at a time. During the debugging process, place a return -1 or return 0; after the transaction to ensure that replay of the script goes only until the transaction that we are currently working. Apply all the concepts like parameterization, correlation, page verification, think time and transactions for this transaction and replay to ensure that the script is working fine until the current transaction.
Note: return -1 will stop the execution of the script whereas return 0 will stop only the current iteration. To understand the difference, try setting the Runlogic to more than 1 iteation.

·         Correlation Challenges: The most probable reasons that a dynamic data is not captured is
o   The Left and right boundaries defined in the correlation function can be wrong – Be sure to check for the additional spaces, Tab Vs. spaces, escaping the double quotes
o   The placement of correlation function – Majority of the cases, the dynamic data should be available in previous request’s response. However, this may not be true always. Be sure to identify the request that receives the response with dynamic data and the correlation function should be placed above such request
o   Size matters – if huge dynamic data (Ex: Viewstate) is to be captured, be sure to specify the max length of the LR parameter by using the function web_set_max_html_param_len() function before capturing the dynamic data
o   Ensure dynamic data is generated by server – While 95% of the cases the dynamic data is received in server response, there is also a chance that the dynamic data is generated by client side java script as well (Ex: Hashcode generator). In such cases, the java script code needs to be identified and integrated with the script using web_js_run() function

·         Headers are crucial – LoadRunner is able to handle all the standard headers by default. However, if the request contains custom headers, those need to be added in the script explicitly with the functions web_add_header() / web_add_auto_header(). The easiest way to identify if the script is missing on any custom headers is to compare the snapshot information / Advanced trace in Log settings with network sniffing data (either from Developer tools or Fiddler session’s data)

·         Encoding data – web_url() and web_submit_data are capable of handling URL encoding automatically whereas the web_custom_request expects the form data as is. Hence, if the raw data of the request contains the URL encoding, be sure to convert the text into URL encoded form by using the function web_convert_param()

     As long as the request triggered from LoadRunner is same as the one from the browser, the scripts should work fine without any issues. Simulating the exact same request to that of the browser is the key while debugging the script.


Monday, September 8, 2014

Find Sub string from captured value in LoadRunner

This article discusses the about how we can find a sub string from a captured LR parameter by specifying an LB and RB in the captured value . We use web_reg_save_param_ex() / web_reg_save_param() or web_reg_save_param_regex() function to capture the dynamic data from the server response.

In majority of the cases the attributes used with the correlation function are good enough to capture the exact dynamic data. We can either use the attributes "SaveLen", "SaveOffset", or text flags to capture the exact dynamic data. We can also use the regular expressions to capture the exact values.

The function that is most helpful in this case is lr_save_param_regexp() where you can pass the LR parameter and specify the regular expression as below:



 lr_save_param_regexp (lr_eval_string("{DynData}"),
                     strlen(lr_eval_string("{DynData}")),
               "RegExp=(to.*?by)",
               "Ordinal=All",
               "ResultParam=reMatchesParam",
               LAST );

Now the above function would retrieve all the occurrence of strings that match the regular expression to and some string followed by by. Now the sample output of the above statement can be as below:

Action.c(7): Notify: Saving Parameter "reMatchesParam_1 = to performance by".
Action.c(7): Notify: Saving Parameter "reMatchesParam_2 = to selenium by".
Action.c(7): Notify: Saving Parameter "reMatchesParam_3 = to management by".
Action.c(7): Notify: Saving Parameter "reMatchesParam_4 = to sales by".


The only problem with the above statement is that, it is introduced in the new version LoadRunner. Below is the "C" implementation of the same.


FindAllSubStrings(char *Src, char *LB, char *RB, char * LRParam)
{

    char buff[1000], temp[100];
    char *pos1, *pos2;
    int offset, i=0;

    // Capture the position of Left boundary
    pos1 = (char *)strstr(Src, LB);
 
    //If the RB and LB both are the same, ensure that you search for RB only after LB
    if(pos1 !=0)
        {
            pos2 = (char *)strstr(pos1 + strlen(LB), RB);
        }
 
    do
    {
        // Make Buff an empty string
        strcpy(buff, "");
     
        // Should return only if both Pos1 and Pos2 are not null
        if(pos1 !=0 && pos2 !=0)
        {
            //Measure the length of the string that is to be saved into the LR parameter
            offset = (int)(pos2 -(pos1+strlen(LB)));
         
            //Save the sub string into the buff variable
            strncat(buff, pos1+strlen(LB), offset);
            i++;
            //Create the LR parameter for example "TestData_i" where i will be incremented wtih each iteration
            sprintf(temp, "%s_%d",LRParam,i);
            //Save the sub string into the parameter "TestData_i"
            lr_save_string(buff, temp);
         
            //change the pointer from where you should look for the next LB and RB
            Src = (char *)(pos2 + strlen(RB));
         
        }
        pos1 = (char *)strstr(Src, LB);
        if(pos1 !=0)
        {
            pos2 = (char *)strstr(pos1 + strlen(LB), RB);
        }
        //Repeat the process until all the values are stored to the LR parameters
     
    }while(pos1 !=0 &&pos2!=0);
 
    //Create an LR parameter that stores the count of sub strings for example "TestData_count"
    sprintf(temp, "%s_count", LRParam);
    //Save the count into the created parameter
    lr_save_int(i, temp);
 
    return 0;
}

The additional advantage of having this function is, because this is a C implementation this function can be used with any version of LoadRunner. The only modification that may be needed to change the size of the variables used in this function.  

The usage of this function is similar to that of Replacer function that I shared earlier.

Please let me know if you have any questions. If you like this article, please hit +1 / Like / Tweet / Comment.

Friday, September 5, 2014

Customizations for performance scripts



Once a navigation has been recorded using the performance testing tool, the recorded script should be customized such that the same script works fine for different users who can choose different things in the same navigation.

Below are the 5 important customizations made to any performance script
Parametrization – To simulate different user inputs, a script should be parametrized. To be more specific, any text field that is seen in the navigation (or the use case) should be parametrized. The best example for this is the user name and password or search text entered in search box. The most common way of parametrization is reading the values from a file.

Correlation – To achieve different user selections, that navigation should be correlated. This also means handling all the dynamic data in a particular request. From the application point of view all the Radio buttons, Drop-down fields, check boxes can be handled by implementing correlation in the script. But the performance tester should also ensure that any other dynamic data that is sent to the server as part of the request should also be handled using correlation.

Page Verification / Validation – Another important aspect of performance testing is validating the response. This can be achieved by having Text validation from the response. A text that is expected in the response should be searched and if the text is found, the request is assumed to be successful else, the request would be considered as a failure. Enough care should be taken while choosing this text that is to be searched for. The text should be static, specific to that particular response and preferably towards the bottom of the response

Transactions – One of most important reasons a performance test is executed is, to figure out the time it takes for the pages to load. To measure this time, the scripts should be included to have transactions

Think time: To simulate the user behavior of waiting between the requests either to read / fill in details (write) or to think if the content is appropriate or not, think time is used in the script.  Once the thread / virtual user receive response for the previous request, they would wait for the specified time before sending the next request.

Irrespective of tool, these customizations (whatever applicable) are made to all the requests in the navigation. Hope this information is helpful. If you like this article, please like it / Share it.


Wednesday, August 13, 2014

String Replacer function for LoadRunner scripting

This article discusses the replacer function that may be needed in LoadRunner scripting. We use web_reg_save_param_ex() / web_reg_save_param() function to capture the dynamic data from the server response. One of the attributes that this function supports is the "Convert" either from HTML_TO_URL or HTML_TO_TEXT.

One can also use the function web_convert_param() explicitly to convert the HTML content to either URL encoded format or to a Plain Text. However, this function may not serve purpose all the time and sometimes a performance tester may need to convert a captured value to something else by explicitly replacing a sub-string with another.

For example: The dynamic value captured from the server response is "Welcome To Performance Testing Training Online" and the next request sends the data Welcome**To**Performance**Testing**Training**Online". It is clear that the Space in the dynamic data is replaced by **.

To replace every space in the dynamic data with  **, the string replacer function below is helpful.


char *Replacer(char *capValue, char *replace, char *replacewith)
{
char *pos;
int offset;
char output[1000];

pos = (char *)strstr(capValue, replace);
strcpy(output, "");
while(pos!=0)
{
offset = (int) (pos - capValue);
strncat(output, capValue, offset);
strcat(output, replacewith);
capValue = (char *) (pos + strlen(replace));
pos = (char *)strstr(capValue, replace);
}
strcat(output, capValue);
//lr_output_message("%s", output);
return output;
}

All that is needed is you can add this code before your action function or you can Add new files to script and copy paste the code there so that the function can be reused any number of times.

All that you need to do is call the function as below:

temp = Replacer(lr_eval_string("{DynData}"), " ", "**");
lr_save_string(temp, "ModDynData");

With the above two statements in your action block, all the spaces in dynamic data are replaced with ** and the modified data is saved to an LR parameter called "ModDynData".

Please note that the above function primarily depends on the strstr function to identify all the spaces in the dynamic data. To understand better about the strstr function, please read my previous blog.

If you like this blog and article please click on +1 or comment. Please feel free to share about this blog with your friends.

Sunday, August 10, 2014

strstr function in LoadRunner

The most common problem that a performance tester face with automation in LoadRunner is string manipulations. To understand and implement string manipulations, one need to know the important functions that are used to do so. the function strstr() is one of the most important functions that are used for string manipulations.

The function strstr() returns the address location of a sub-string in a main string. If the sub-string is not found in the main string, the function would return zero. Hence this function can be used to validate if a sub-string is found in the main string or not.

To understand the function better, let us consider a small example:

char MainStr[1000] = "Welcome to Performance Testing Training online";
char SubStr[10] = "Train";
char * position;

position = (char *)strstr(MainStr, SubStr);

In the above example, when a MainStr variable is declared, a variable is created and 1000 bytes are allocated and the variable "MainStr" contains the starting address location. Let us assume that in the current example the Memory address location allocated for the variable MainStr is from 12001 to 13000. Now the variable MainStr contains the address location 12001.

When the strstr() function is executed, the compiler looks for the characters in the substring starting from the first address location i.e. 12001 in this case. Now, the first character in the SubString is 'T' which would be first found at the address location,  12024 (as in Testing), however the second character in the Substring does not match with the character in the next address location. So, the compiler ignores the address location 12024 and proceeds further scanning for the character 'T' which would be found at the location 12032. All the subsequent characters do match with the characters in the subsequent address locations and hence the function strstr would the return the address location 12032. The function is type casted such that the return value is explicitly defined as character pointer.

This is the most used function for most of the string manipulations and the coming blogs illustrate the usage of this function.

I hope this information is useful. If you like the content in this blog, please click +1/ Comment. Please feel free to share with your friends.

Wednesday, July 23, 2014

Using analytical data for measuring the concurrency




The most important thing as part of requirement gathering for a performance testing engagement is to measure the concurrency that has to be simulated/generated. A performance tester needs to get access to the server logs / Analytical data to perform this action.

Let us take a small example of a restaurant which says they server around 1500 customers a day for lunch, where the lunch hours being 12:00 – 3:00 PM. This translates to 500 customers every hour during their lunch time. Now the key factor here is the average duration of a customer.

If people spend an hour for their lunch, it means that the restaurant has to accommodate 500 people in one slot. Assuming that the average time spent at lunch is 30 minutes, now the restaurant has to accommodate only 250 users. 

Now the number either 500 or 250 is the number of customers having their lunch at the same time, which is also known as concurrency.

This is exactly the same way that we calculate the number of concurrent users on the system. The important factors to be considered while calculating the concurrency are:

  • The average duration of a visitor on the application
  • Total number of visits on a peak day / peak hour

Now to get the above said statistics, one can either configure Google analytics on the application or refer to Web server logs that have the information about the user session start time and end time. The third alternative is to get these statistics from the Business analyst in case if the target load is a forecast or prediction for the future (like the coming thanks giving day / Christmas Eve / Memorial Day/ Super bowl day etc.)

The scientific way of calculating the concurrency is to use little’s law. The little’s law says  The long-term average number of customers in a stable system L is equal to the long-term average effective arrival rate, λ, multiplied by the average time a customer spends in the system, W; or expressed algebraically: L = λW.” For more details on little’s law refer wiki (http://en.wikipedia.org/wiki/Little's_law )

The total number of users on a web application can be determined by the average arrival rate (100 users / hour and average time spent in the application 1/10 hours (i.e. 6 minutes). Now the concurrency at any point of time L = 100*1/10 = 10 users.
Hope this information is helpful in determining the target user load for an application.

Wednesday, June 25, 2014

Being / Becoming a Performance Tester


If you wanted to become a performance tester or make your career in performance testing, below are the important characteristics that you need to have:

Common Sense and observation
There are several jobs which do not require applying common sense or minute observation skills. But Performance testing is not definitely one of those. You should have lot of observation as well as common sense.

Jump into the shoes of others:
The performance testing job expects you think from the various perspectives like from the customer / end user point of view, from the business point of view / from the application / technology point of view etc.  While automating the use cases you should think from the end user perspective. When providing a performance test report, you should ensure that the report can be understood for the business analysts as well as the one who owns the entire business. While analyzing the root causes for the performance issues, you should imagine yourself as a technologist.

Willingness to Learn:
Learning performance testing is not one time activity, though the basics remain the same. With the new technologies emerging pretty quickly, as a performance tester you should upgrade yourself to the new technologies and understand the core of them. Continuous learning is the one vital factor that makes a performance tester career prolonged.

The above said are the basic things needed. However, to start your career as a performance tester below is the technical stuff that you should have at least basic understanding about
Operating systems: How operating systems work, the CPU scheduling, memory management, disk management etc
Databases: The tables, queries, joins and indexes and how a query is executed
Computer networks: How the communication between the client and server happens, the TCP, UDP communications, HTTP
Web Application architecture and browser properties: Web, App and DB Servers, the way they work, some important features of web applications like session ID, cookies, request methods and response
Any programming language – You should be good in writing the basic programs with any one programming language

So, if you are considering a career in performance testing, ensure you have all the above said requirements met.

Monday, June 9, 2014

Understanding Randomization in LoadRunner

Randomization is a common practice with majority of the performance test scripts, where dropdown / Radio buttons / Links has to be chosen by the user randomly.

For example the application requires choosing a value from the drop down randomly, then the important thing is to know how many values are there in the drop down and what their values.

We all know the web_reg_save_param() or web_reg_save_param_ex() function has to be used to capture the values. Now, because we need all the values we'll specify the attribute "ORD=ALL" / "Ordinal=all". Assume that the function is written as below:

web_reg_save_param("DropdownValues", "Lb=<option>","rb=</option>", "Ord=all", LAST);

When the above function is executed, LoadRunner creates N+1 LR variables if there are N values in the drop down.

The first drop down value will be saved to an LR variable named "DropdownValues_1" and the second value from the drop down will be save to an LR variable named "DropdownValues_2" and so on. The total number of matches / count would be saved to another parameter called "DropdownValues_count".

The function used to choose a random value is lr_paramarr_random(). This function returns an address location of the random parameter.

In our example the function should be used as:

char * randVal;


randVal = lr_paramarr_random("DropdownValues");

As the variable randVal is C string variable, cannot be used in protocol functions,  this has to be converted to an LR parameter using below statement (for details on why, please refer to variable conversion in LoadRunner).
lr_save_string(randVal, "RandDropdownVal");

When lr_paramarr_random("DropdownValues") is seen the script, the script immediately checks if there is a parameter named "DropdownValues_count" and tries to retrieve its value. If this parameter is not available, an error would be thrown.

Assuming that the count is 10, now it generates a random value between 1 -  10 and refers to the corresponding address location. i.e. if the random number is 6, it searches if there is an LR parameter called "DropdownValues_6", if yes,  its address location is returned to the string variable.

If there is no such parameter, it would throw a warning saying that "The string with parameter delimiters is not a parameter"

Hence it is very important to capture all the values using the web_reg_save_param() function with the ORD attribute set to ALL if at all the parameter has to be used for randomization.

In the next article, we will see how we can utilize this behavior in building a custom C function that works similar to web_reg_save_param() with ORD being set to ALL.


Monday, May 19, 2014

in LoadRunner Did you Know?

  • Save the current times tamp in Milli seconds to an LR parameter can be achieved with the function web_save_timestamp_param()
  • web_url() and web_submit_data() are capable of the encoding the form data automatically. But web_custom_request() cannot encode the form data automatically. The encoding can be done by the function web_convert_param()
  • Automation of the windows based web applications (that uses NTLM authentication) uses the web_set_user() function for sending the username and passwords. While replaying the script, it is recommended to use the run time setting Preferences --> Advanced -->WinInet Replay instead of Sockets
  • Reading and writing from the same file can be achieved by Virtual Table Server
  • The function lr_paramarr_random("x") first validates if there is an LR parameter called x_count, if there is no such parameter, it returns an error
  •  The function web_global_verification() works same as the run time setting Content check, except that the global verification can be paused and resumed with the functions web_global_verification_pause() and web_global_verification_resume()

Thursday, May 8, 2014

Variable conversion in LoadRunner

In the last post, I have given an overview on what types of variables are seen in an LR Script and where they should be used.

This article covers on conversion of LR Variables to C Variables and viceversa.  There are three important LR functions used for the conversion. 
We'll  see one at a time.

lr_eval_string()
This function evaluates a load runner variable and returns its value if placed in flower braces. Let us try to understand how it really works.

lr_eval_string("test") returns a string called "test"
lr_eval_string("{test}") - Now this function checks if there is LoadRunner variable called test or not. 
If there is a LoadRunner variable named test and its value is "Welcome". Now the function lr_eval_string("{test}") returns a string "Welcome"

If no LoadRunner variable exists with the name test, then the function lr_eval_string("{test}") returns a string "{test}"

Now let us see two more last example of lr_eval_string() function:

Assumption: There is an LR variable called test whose value is "{Welcome}". There is another LR variable called Welcome whose value is "Performance Testing Online".

lr_eval_string("{test}") - This returns a string "{Welcome}"
lr_eval_string() function does not do nested evaluation

lr_eval_string(lr_eval_string("{test}"))
 = lr_eval_string("{Welcome}");
 = "Performance Testing Online"

LR to C String
Now that you understand the usage of lr_eval_string() function let us see how we can convert an LR Variable to C string variable.

char CStr[100];

to save "Performance Testing Online" into the string variable CStr, the syntax is:

strcpy(CStr, lr_eval_string(lr_eval_string("{test}")));

Please note that an equal symbol (=) cannot be used to assign a value to a string variable. We will have a separate article on why.

So, the conclusion is, to save an LR value to a C string variable, the lr_eval_string() function is used.

Now let us see, how we can convert an LR Parameter to C integer variable
 
let us assume that the LR variable test stores a value of "10".

LR to C Integers
This value should be converted to a string format first using lr_eval_string() function. This function returns a string value. To convert a string value into an integer, we have C function called atoi() read it as A to I (meaning alphabets to Integers)

int Count;

Count = atoi(lr_eval_string("{test}"));

This is how a value in LR variable is saved to a C variable. Though the heading says converting an LR variable to C variable, in fact we are storing the value of an LR variable into a C variable.

Now let us see the otherway i.e. converting a C integer / String to an LR parameter.

we have two functions named lr_save_string() and lr_save_int() to save a string and integer values to an LR parameter respectivily.

C to LR
int i = 256;

lr_save_int(i, "Total"); 

Now Total is an LR variable which stored a value of 256 in it. Inside the web_url() or web_submit_data or web_custom_request it can be used as {Total}

char Text[100] = "Welcome to Performance Testing Online";

lr_save_string(text, "Status");
Now Status is an LR variable which stored the entire string in it. In a web request it should be used as {Status}


I hope this article is informative and helpful.  If you have any questions, please feel free to comment.


Thanks,
Ram N