Вы находитесь на странице: 1из 37

Today, I will explain - what is LoadRunner correlation and how to perform it.

In my humble opinion, correlation is the key concept of LoadRunner. So,


strong understanding of correlation is mandatory requirement for any test
engineer, if he plans to be LoadRunner professional or even guru :)

Example from a real practice:

I recorded LoadRunner script for a web server, which contained two special fields
- timestamp and checksum:

web_submit_data("rms.jsp",
"Action=http://eprumossd0010:8400/RMS/jsp/rms.jsp",
"Method=POST",
"RecContentType=text/html",
"Referer=http://eprumossd0010:8400/RMS/html/testFramework.html",
"Snapshot=t4.inf",
"Mode=HTML",
ITEMDATA,
"Name=TIMESTAMP", "Value=1192177661211", ENDITEM,
"Name=CHECKSUM",
"Value=715E19300D670ED77773BBF066DAAAE2866484B8",
ENDITEM,
// others parameters ...
LAST);

Every time a client web browser connects to web server, server gets current time
stamp, calculates checksum and sends them to client. These two fields are used to
identify a current session. In other words, the pair of timestamp+checksum is
analog of session ID.

The scheme of this interaction is the following:

Where is the problem? Let's replay the recorded LR script.

The problem occurs when I try to execute my recorded script.


Web server checks its current time with a time stamp, sent by client. If client's
data is out-of-date or incorrect, then server returns an error:

The parameter "CHECKSUM" is not found or has invalid value.

There is the scheme for this interaction:

Client cannot re-use old


(i.e. hard-coded) values for times tamp and checksum. It must request new data.
So, instead of hard-coded values, LR script should process dynamic data,
returned from server. This can be done using a correlation:

The definition of correlation is:


Correlation is the capturing of dynamic values passed from the server
to the client.

Correlation can be done with 2 ways:

1. Automatically
2. Manually

I will describe auto-correlation in the future posts. For now, I can say that this is
not ideal solution. Sometimes, it does not work, or works incorrectly.

Manual correlation is a choice of real LoadRunner engineer. It's a kind of "must


have" knowledge!
Well, let's start investigating a manual correlation.

The algorithm of manual correlation is the following:

1. Find a dynamic value to capture.


2. Find server's response, containing the dynamic value.
3. Capture the dynamic value.
Special parameter will be used instead of dynamic value.
4. Replace every occurrence of dynamic value in script with the parameter.
5. Check changes.

Now, I will describe each step in details:

1. Find a dynamic value to capture


I recommend to record and save two equal VuGen scripts. After that, open
menu item "Tools / Compare with Scripts..." and you can compare both
recorded scripts in WDiff:

The differences
are highlighted by yellow. This highlighting means that lines (parameters
values) change from run to run. So, most probably, these values should be
correlated.

Tips: Sometimes, comparing of two scripts cannot detect dynamic values.


Imagine, that you recorded this script:
"Name=SessionID", "Value=A38E9002A41", ENDITEM,
"Name=CurrentMonthID", "Value=4", ENDITEM,
...
It's obvious, that SessionID should be correlated. What about
CurrentMonthID parameter? Second recorded script can contain
"Value=4" too. And it's possible, that your script will work correctly during
the April (4th month is April), and will not work from 1st May! So, be
careful, my dear reader :)

Tips: Look through the source code of recorded script. Timestamp,


CheckSum, SessionID, and different IDs - all of they are potential
candidates to be correlated.

Tips: Check Replay (Execution) log carefully. Errors can be there. The
widespread reason of script's errors is an absence of correlations.

Tips: Execute your script with enabled run-time viewer (menu "Tools /
General Options.. / Display"). Any shown errors ("Page not found",
"Session timeout", etc) indicate about potential correlations.

2. Find server's response, containing the dynamic value


Before script executing, please enable extended logging from "Vuser /
Run-Time Settings...":

Then execute
script.
Open Replay (Execution) log and find server's response, which contains
dynamic values of TIMESTAMP and CHECKSUM:

Great! Now we
know, where server sends both dynamic values.
And we found the step, that returns these values. This is 13th line -
Action.c (13). Double click the line, containing timstamp's and checksum's
values, 13th line of script will be opened:
web_submit_data("generateChecksum.jsp",
"Action=http://eprumossd0010:8400/RMS/jsp/generateChecksum.jsp
",
"Method=POST",
"RecContentType=text/html",
...
This means that server's response for generateChecksum.jsp page contains
dynamic values which should be correlated.
3. Capture the dynamic value
I will show two ways how to capture a dynamic value:
o Automatic capturing from Tree-view
o Manual from Script-view

These ways are similar enough. Also, they use the same function -
web_reg_save_param.

I start from:

o Automatic capturing from Tree-view.


Open Tree view (menu "View / Tree view"):

Then:
 click "View recording snapshot only" btn (2);
 select generateChecksum.jsp page from tree view (3);
 select "Body" to view body of server's response (4).

As result, you will see recorded values of CHECKSUM and


TIMESTAMP (5).

Now, select value of first dynamic value (checksum), right-click,


and select "Create parameter":

After that
you will see the message box:

You can
create parameter for dynamic value.
If you want to replace all occurrences of dynamic value ("715E19...")
in script, press "Yes" btn.
To not replace all occurrences, press "No" btn.

Tips: I recommend to not replace all occurrences of dynamic value.


It can lead to incorrect results. It's more preferable to replace
occurrences one by one with "Search and Replace" dlg.

OK, I click "No" btn.

Return to Script-view ("View / Script View") and see changes. There


are new lines, inserted before generateChecksum.jsp page:

// [WCSPARAM WCSParam_Text1 40
715E19300D670ED77773BBF066DAAAE2866484B8] Parameter
{WCSParam_Text1} created by Correlation Studio
web_reg_save_param("WCSParam_Text1",
"LB=window.parent.setChecksum(\"",
"RB=\"",
"Ord=1",
"RelFrameId=1",
"Search=Body",
"IgnoreRedirections=Yes",
LAST);

web_reg_save_param function finds and saves a text string from


the next server's response. In other words, it captures a dynamic
value.

In this example, web_reg_save_param function will save the


captured value into WCSParam_Text1 parameter. The function
finds the left boundary (window.parent.setChecksum(") and after
that it finds the right boundary ("). The string, found between left
and right boundaries, will be saved to WCSParam_Text1 parameter.
Ord attribute indicates the ordinal position of captured value. In the
example (Ord=1), we capture the value between first left boundary
and left one.
Easy to guess, that "Search=Body" means search in a body of
server's response.
I recommend to study Help on web_reg_save_param function. It's
very interesting :)

Note: the capturing of TIMESTAMP parameter is similar. It


generates the following code:

// [WCSPARAM WCSParam_Text2 13 1192177661211] Parameter


{WCSParam_Text2} created by Correlation Studio
web_reg_save_param("WCSParam_Text2",
"LB=, ",
"RB=)",
"Ord=1",
"RelFrameId=1",
"Search=Body",
"IgnoreRedirections=Yes",
LAST);

o Manual capturing from Script-view.


Actually, this method consists in a manual writing of
web_reg_save_param function. It requires strong knowledge on
this function and its parameters. There are many attributes of
web_reg_save_param function, and I do not want to duplicate HP's
Help :)

Tips: I recommend to rename default parameter


(WCSParam_Text1, 2, 3, etc) to something sensible. For example,
in my example - I would prefer prmCheckSum and prmTimeStamp
to WCSParam_Text1 and WCSParam_Text2.

4. Replace every occurrence of dynamic value in script with the


parameter
This is not difficult step.
Open "Search and Replace" dlg ("Edit / Replace..."). And replace one-by-
one hard-coded values with a parameter.

Why it is important?
Imagine, that you have the following code:

web_submit_data("somepage",
...
"Name=OrderNumber", "Value=125", ENDITEM,
"Name=UserID", "Value=125",

If you create parameter for UserID, and perform replacing of all


occurrences of its value ("125"), then it will produce the code:

web_submit_data("somepage",
...
"Name=OrderNumber", "Value={WCSParam_Text1}", ENDITEM,
"Name=UserID", "Value={WCSParam_Text1}",

It may be wrong! OrderNumber can be static value and be equal to 125,


while UserID may change.

Now, I assume that you replace all needed occurrences of hard-coded


values. We have to perform last step:

5. Check changes
After above manipulations, our script will look like:

web_submit_data("rms.jsp",
"Action=http://eprumossd0010:8400/RMS/jsp/rms.jsp",
"Method=POST",
"RecContentType=text/html",
"Referer=http://eprumossd0010:8400/RMS/html/testFramework.htm
l",
"Snapshot=t4.inf",
"Mode=HTML",
ITEMDATA,
"Name=TIMESTAMP", "Value={WCSParam_Text2}", ENDITEM,
"Name=CHECKSUM", "Value={WCSParam_Text1}", ENDITEM,
// others parameters ...
LAST);

The statement "{WCSParam_Text1}" means "get value of


WCSParam_Text1 parameter".
So, current algorithm is:
o when server returns different values of CheckSum and TimeStamp
o then web_submit_data captures and places them into
WCSParam_Text1 and WCSParam_Text2 parameters
o after that we use {WCSParam_Text1} and
{WCSParam_Text2} get current values of parameters and use
them in scripts

Let's run our modified script and see results of capturing from server's
response:

These are values,


which are sent to a server by a client:

You can see that dynamic values are saved to parameters and their values
are substituted instead of parameters in scripts. Great! We have just
correlated our script and it is working now!

Tips: To get/debug a captured value of parameter, use the following


statements:
lr_output_message("Value of WCSParam_Text1: %s",
lr_eval_string("{WCSParam_Text1}"));
lr_output_message("Value of WCSParam_Text2: %s",
lr_eval_string("{WCSParam_Text2}"));
Execute script again, he result is:

Regular Expression in load Runner


I'm going to show and explain how to use Regular Expressions in
LoadRunner.

Introduction:
The present article is a summarizing of the LoadRunner Regular Expressions
challenge and its results. Also, I added code for RegExp patterns/subpatterns
matching.
All LoadRunner Regular Expressions functions are shown with examples.

Outline:

1. How to check - whether RegExp pattern matches against a text


or not
2. How to get a matched strings (RegExp patterns and
subpatterns)

How to check - Whether RegExp pattern matches against a text or not

I thanks Charlie Weiblen and Tim Koopmans for the solution. I modified it
slightly.
So, here it is:

1. Download and unpack Binaries and Developer files for PCRE (Perl
Compatible Regular Expressions).
These and others files are available on Pcre for Windows page.
2. Unzip downloaded archives into c:\pcre

3. Сomment out the include for stdlib.h file in:


o C:\pcre\include\pcre.h
o C:\pcre\include\pcreposix.h

4. In your LoadRunner script, add to globals.h:


o #include "c:\\pcre\\include\\pcre.h"
o #include "c:\\pcre\\include\\pcreposix.h"

5. Add the match() function to vuser_init section:


//////////////////////////////////////////////////////
////////////////////
/// 'match' function matches a 'pattern' against a
given 'subject'
/// It returns 1 for a match, or 0 for a non-match /
error
int match(const char *subject, const char *pattern)
{
int rc; // Returned code
regex_t re; // Compiled regexp pattern

lr_load_dll("c:\\pcre\\bin\\pcre3.dll");

if (regcomp(&re, pattern, 0) != 0)
return 0; // Report error

rc = regexec(&re, subject, 0, NULL, 0);


regfree(&re);

if (rc != 0)
return 0; // Report error
else
return 1;
}

6. Let's run sample LoadRunner script and check the result:

As you can see,


match() function works correctly. Using match() function, you can
check - whether RegExp pattern matches against a text or not.

It can be helpful, when you verify in LoadRunner that the text (RegExp
pattern) matches the text on a downloaded page.

I tested the match() function with different patterns and subject strings:
Result of Is correct
# Subject string Patterns
match() result?
1 abcdef b(c(.*))e 1 Yes
2 abcdef b(z(.*))e 0 Yes
3 2008 \\d{2,5} 1 Yes
4 2008 \\d{5} 0 Yes
5 abc 1st of May 2008xyz \\d.*\\d 1 Yes
7. Note: Since LoadRunner uses ANSI C language, please do not forget to
double backslashes (\\). For example, to match any digit character (0-9),
use pattern "\\d".

match() function is simple enough. But it searches only and it cannot


extract matched subpatterns from the text. For example, we have to
extract the name of month from these strings:
o "abc 1st of May 2008xyz"
o "abc 25th of February 2031"
o etc

We can use the following pattern:

o \d.+([A-Z]\w+)\s+\d{4}

The name of month will be matches by subpattern ([A-Z]\w+). How to


extract the found text? You can use matchex() function for that. Let's
discuss it in details...

How to get a matched strings (RegExp patterns and subpatterns)

To get a matched (found) strings, we have to update our match() function.


That's why I created matchex() ('match' EXtended) function.

1. Add the matchex() function to vuser_init section

//////////////////////////////////////////////////////
////////////////////
/// 'matchex' (EXtended) function matches a 'pattern'
against a given 'subject'
/// It returns number of matches:
/// 0 - for a non-match or error
/// 1 and more - for successful matches
int matchex(const char *subject, const char *pattern,
int nmatch, regmatch_t *pmatch)
{
int rc; // Returned code
regex_t re; // Compiled regexp pattern

lr_load_dll("c:\\pcre\\bin\\pcre3.dll");

if (regcomp(&re, pattern, 0) != 0)
return 0; // Report error

rc = regexec(&re, subject, nmatch, pmatch, 0);


pcre_free(&re); // Release memory used for the
compiled pattern

if (rc < 0)
return 0; // Report error

// Get total number of matched patterns and subpatterns


for (rc = 0; rc < nmatch; rc++)
if (pmatch[rc].rm_so == -1)
break;

return rc;
}
2. Let's run sample LoadRunner script and check the result:

matchex()
function returns a number of matched patterns/subpatterns and fill an
array in with information about each matched substring.

What is an information about each matched substring?

This info contains the offset (rm_so) to the first character of each
substring and the offset (rm_eo) to the first character after the end
of each substring, respectively.

Note1: The 0th element of the array relates to the entire portion of
string that was matched.
Note2: Subsequent elements of the array relate to the capturing
subpatterns of the regular expression.
Note3: Unused entries in the array have both structure members set to
-1.

Let's investigate it with the example. This is our subject string:

The replay
log shows offsets for matched substrings:
o Action.c(7): Matched 3 patterns
o Action.c(10): Start offset: 1, End offset: 6
o Action.c(10): Start offset: 2, End offset: 5
o Action.c(10): Start offset: 3, End offset: 5
Start offset: 1 and End offset: 6 match substring "bcdef".
Note4: End offset is the first character after the end the current
substring. That's why character "g" (with index 6) is not a part of matched
string.

As I've written in Note1, "bcdef" is the entire portion of string that was
matched.
Others items from an array relate to matched subpatterns.

What is a subpattern in Regular Expression?

It is a part of the RegExp pattern surrounded with parenthesis - "(" and


")".

It's easy to get out the order of subpatterns. Just look through your pattern
from left to right. When you find an open parenthes, this is a start of the
current subpattern.
Subpattern can be embedded.

So, others captured subpatterns are:

o Start offset: 2, End offset: 5 matches substring "cde".


Note: current subpattern is "([acqz](.*))".
o Start offset: 3, End offset: 5 match substring "de".
Note: current subpattern is "(.*)".

As you can see - this is not so difficult. :)


Regular Expressions can be very powerful and useful in LoadRunner.

Another example:

Let's practise with an example I mentioned early:


For example, we have to extract the name of month from these strings:

• "abc 1st of May 2008xyz"


• "abc 25th of February 2031"
• etc

We can use the following pattern:

• \d.+([A-Z]\w+)\s+\d{4}

The name of month will be matches by subpattern ([A-Z]\w+).


Please, see LoadRunner script, which captures and prints name of months:

Note: Pay attention that


I use arr[1] to get info about substring.
As you remember, arr[0] contains info about the entire matched pattern, arr[1],
arr[2], and so on contain info about matched subpattern.

Summary:
I've explained, shown and demonstrated how to use Regular Expressions
(RegExp) in LoadRunner.
I hope, this knowledge will help you to create advanced LoadRunner scripts.

Related articles:

• How to perform basic operations on LoadRunner parameters?


• Using Correlation in LoadRunner scripts - visual tutorial
• Boundaries for web_reg_save_param LoadRunner function
• LoadRunner Correlation - How to capture an array of dynamic data with
web_reg_save_param function
• All LoadRunner visual tutorials

3……Memory Leaks

Today, I plan to share my experience on the memory leaks detecting. This article
is a step-by-step instruction on how to use HP/Mercury LoadRunner to perform
load testing for the purpose of memory leaks discovering.

The task:
It needs perform testing of Web server to discover memory leaks.
The solution:

1. Create LoadRunner VuGen script for your application (Web server in my


script)
Let's suppose, we have done it:

Actually, I will explain different tricks and features of VuGen scripts in the
further posts.
2. Create LoadRunner Controller scenario for your application using the
VuGen scripts.
Here it is:

3. The next step is to add measurement monitors which are quantitative


indicators of resources being monitored (for example, memory usage, CPU
usage, handle and thread count, and so on).
For that, on "Run" tab in the LoadRunner Controller, drag "Windows
Resources" item from the "Available Graphs" tree and drop it to graphs
area.
See the screenshot:
Then right-click on the just added graph ("Windows Resources") and
select "Add Measurements" from the pop-up menu.
"Windows Resources" dialog will be shown:

The following actions are easy. I will add the name of server where the
application (Web server in my case) will be run. This server can be a
remote one. In this case, you have to make sure that LoadRunner will have
an access to get info from the remote computer. Usually, I provide
administrator rights for user which executes LR scripts.
After that I select counters I want to measure during the load testing:
So, "Windows Resources" dialog looks like:

I selected the following counters:


o % User Time for two processes (RService & tomcat5) and the whole
system (_Total)
o Available bytes in the system
o Handle counts
o Thread counts
o Working Sets

Also you may wish to add "Private Bytes" counter. Description for each
counter is available on "Windows Resources" dialog. Obviously that the set
of counters depends on the requirements and software to be tested.
Pay attention... If you select the "Windows Resources" graph, the list of
counters will be shown in the lower part of the LoadRunner Controller:

4. Our mission is almost complete :) We have to run the scenario against a


number of concurrent users (I user 30 users) and observe the graph
displaying info on memory, CPU, handles and so on...
I will show the result graph after 4 hrs of execution:

Pay attention to the yellow dotted line (memory usage of "RService"


process) and the brown dotted line (habdle count counsumed by
"RService" process) trends. They grow constantly during ~ 4.5 hours. I
marked them out with red lines.
So, this graph provides proofs that the application, I tested, contains
memory leaks in the "RService" process.

Several words about useful tricks and hints, connected to measurements


ans graphs:
o It is possible to export graphs to HTML from the LR. For that,
right-click on the graph and select "Export to HTML...". It will
generate HTML report containing the graph and a legenda for it.
Very useful feature :)
o I recommend to set the range of time to be shown on the graph, to
"Relative to scenario start". To perform this, right-click on the
graph and select "Configure...". That allow to display statistics for
the whole execution, but the latest N minutes.
o Sometimes, it is convenient to show more detailed graph. For that,
double click on the graph - one big graph will be shown. To revert,
double-click again. Also, you can change the number of graphs
displayed - open menu View/View Graphs and set the required
number.

5. So, now Dev team has to fix the problem in the "RService" process.. The
last graph shows the results of load testing perfomed on the fixed
application:

No any memory leaks found during 10 hrs.

Memory leaks fixed! Isn't it a progress? :)

Identifying Broken Links ………Load Runner

Today, I will describe how to use LoadRunner for broken links detection.
'Broken' link is 'not valid' link. This link usually returns 404 Error - "Page not
found".
Another side of broken links is that images other resources are not displayed.

Using LoadRunner for broken links detection can be helpful, when you perform
load testing of a site and you have to be sure, that all pages, images, applets, and
other resources are available during the high server loading.

LoadRunner allows broken links detection during:

1. Script recording
2. Script execution

1. Broken links detection during LoadRunner script recording


You have to set appropriate recording options. For that, click 'Options...'
button from 'Star Recording' dialog:

'Recording Options' dialog opens. Here, set 'Add comment to script for
HTTP errors while recording' option:

Please, note that


you can see a description of the 'Add comment to script for HTTP errors
while recording' option.

Now, you are ready to record your script. Click 'OK' button on 'Recording
Options' dialog and start recording.

If LoadRunner find any HTTP errors, it will include comment into VuGen
script.
My application had some problems - there were several broken links for
images there. So, LoadRunner generated the following script (click the
image to view enlarged):

As you see, my
application had several broken links to images and LoadRunner detected it
successfully. Also, you can find the point, where these broken links were
used. This is previous function - web_url.

LoadRunner inserted comments, which describe all occurred HTTP errors.


Comments contain URL and server response.
Since you have server responses, you can determine reasons of HTTP
errors.

Tips: For detailed info on HTTP status codes read this article from
wikipedia and this one from w3.org.
Tips: Read about the most 'popular' HTTP status code - 404.

2. Broken links detection during LoadRunner script execution


LoadRunner can check broken links during the script execution too.
You have to turn off one LoadRunner run-time option - 'Non-critical
resource errors as warnings':
Uncheck the
'Non-critical resource errors as warnings' option and execute previous
script again.
The result is:

Please, note that


LoadRunner's Replay Log contains errors about images we mentioned
before. Their links were broken, that's why LoadRunner generated errors.

I hope, this LoadRunner tutorial was helpful.


As you can see, the initial task - broken links detection with LoadRunner - can be
resolved in two ways.

You have to set appropriate option only. LoadRunner will do the rest :)

Load Runner Analysis Html Reports ………

Introductory words about LoadRunner Analysis HTML reports:


I like watching on how my LoadRunner scripts work without my intervention.
The plan is simple:

• I start LoadRunner Controller from command line


• Controller performs load testing
• After Controller finishes, it opens Analysis
• LoadRunner Analysis analyses :) and interprets results of load tests
• I create and export customized HTML report

Default HTML report looks like the following one:

The task I faced:

After Analysis completed working, custom HTML report should be created and
exported automatically and be sent with email. After that, next load test can be
started from bat-file. So, there are no any pauses for tester's intervention should
be.

My custom HTML report should contain new graph - "Windows Resources".


Also, several default pages should be removed - "Running Vusers",
"Throughput", and "Transaction Summary". So, new HTML report should look
like:
And the main condition is:

• this custom report should be generated automatically every time I


started my production LoadRunner scripts

How I created custom reports before:

Actually, any custom report can be created manually... I added manually new
graph ("Windows Resources"), deleted unnecessary pages, generated HTML
report, saved it, attached to email and sent it.

Why I had to automate the creation of reports:

Above process requires tester's time (= mine). I'm lazy man and don't like
wasting my time for such routine actions.

Another important reason to generate these custom reports automatically is that


I created something like a framework, which:

1. restarts test server


2. configures and starts services of my application to be tested
3. starts LoadRunner tests
4. performs load testing
5. gathers and analyses results from automated tests
6. creates custom reports
7. attaches these reports to email and send to appropriate addressees
8. repeats the above actions for next automated LoadRunner test

I plan to share this framework in the nearest future, if anyone asks it :)

Well, let's start working on the current topic...

I will show how to edit a default report and save it as a template. After that, we
will learn how to start LR Analisys from command line and how to work with a
saved template.

How to create custom report:

I recommend to customize a default report and save it as a template.


To delete "Running Vusers", "Throughput", and "Transaction Summary" pages,
select them in Session Explorer, right-click and select "Delete Item":

The new graph ("Windows Resources") adding is also intuitive. Just right-click
on "Graphs" item and select "Add New Item / Add New Graph":

After that you can select new graph to added. In my case, I selected "Windows
Resources" graph:

Note: if you want to add


"Windows Resources" graph, it must be added to LR Controller. Please, read my
previous post to see how add and process "Windows Resources" graph:
How to detect memory leaks with LoadRunner - visual tutorial

After that I rearrange the current list of graphs. For that just drag any item
(graph) and drop it to required place. It's easy, really :)
After these manipulations, the list will be the same I wished:

Great! The finish is not far :)


Now I select menu "Reports / HTML Reprot..." and get the report I dreamt :)

The next step is saving of the current report as a template:

Select menu item "Tools / Templates / Save As Template...".


As a result, "Save As Template" dlg will be shown:

I perform the following:

• Uncheck "Automatically apply this template to a new session" checkbox.


This will allow to load default template when I start LoadRunner Analysis.
Unchecked option suits me.
• Check "Generate the following automatic HTML report" checkbox.
If checked, the HTML report will be generated automatically. This is what
I need.
• Check "Automatically save the session as" checkbox.
It should be checked to correctly automatically close Analysis.
• Check "Automatically close Analysis after saving session" checkbox.
I recommend to enable this option. It will be irreplaceable, if you plan a
batch processing - that's our case.

So, prepared "Save As Template" dialog is shown on the screen shot:

Click OK btn to save new


template.
Close LoadRunner Analysis. Now we are ready to perform last action.
Start LoadRunner Analysis from command line:

• To start only Analysys, execute the following command:


path_to_AnalysisUI.exe

• To open *.lrr file (LoadRunner result file) or *.lra file (LoadRunner


Analysis file), execute:
path_to_AnalysisUI.exe -RESULTPATH path_to_lrr_or_lra_file

• To open *.lrr or *.lra file and apply a specified template, execute:


path_to_AnalysisUI.exe -RESULTPATH path_to_lrr_or_lra_file
-TEMPLATENAME name_of_template

There is an example for my template ("WinResTemplate"):


"c:\Program Files\Mercury\LoadRunner\bin\AnalysisUI.exe"
-RESULTPATH C:\Temp\30users\30users.lrr -TEMPLATENAME
WinResTemplate

Tips on the example:

1. Since path to AnalysisUI.exe contains spaces, use quotes (")


2. You have to specify name of template, not path!

That's all! Execute the example command from command line.


You will see that:

1. Analysis will be loaded


2. It will start processing lrr-file, which was produced by LoadRunner
Controller.
3. After it precesses lrr-file, Analysis will apply template. That means, needed
graphs only will be created. We have specified these graphs above.
4. Analysis will create HTML report
5. HTML report will be saved in specified path (I used - %ResultDir
%\Windows_Resources_Report.html)
6. At the end, Analysis will be closed.

So, custom HTML report is ready without tester's intervention! Next LoadRunner
test can be started from command line.

6. Running Load Runner from Command …….


Today I will explain how to open and run LoadRunner Controller scripts
from command line.
This feature can decrease tester's manual efforts and thereby to increase your
effectiveness and performance.

You can open LoadRunner Controller scenario with:

LoadRunner\bin\Wlrun.exe -Run -TestPath scenario.lrs -ResultName


res_folder

For example:

(note: click the image to


enlarge it)

As a result of above command, LoadRunner Controller:

• starts
• opens Controller scenario
• executes it
• saves results to folder 'C:\Temp\LR_Res\result_0'

After that, Controller finishes working and closes.


Please, see files from created 'C:\Temp\LR_Res\result_0' folder:

Tips: As you see, there is


LoadRunner Result file (result_0.lrr). You can pass it automatically to
LoadRunner Analysis for further processing.
Refer for detailed information: Custom HTML report in LoadRunner Analysis
from command line.
Actually, Wlrun.exe can have several settings. There are their descriptions from
HP LoadRunner Controller User's Guide (© HP/Mercury Interactive):
Path to the scenario.
For example,
TestPath C:\LoadRunner\scenario\Scenario.lrs
If the path includes blank spaces, use quotation
marks.
Runs the scenario, dumps all output messages
Run
into res_dir\output.txt and closes Controller
Instructs LoadRunner to invoke Analysis upon
InvokeAnalysi scenario termination. If this argument is not
s specified, LoadRunner uses the scenario default
setting.
Full results path. For example,
ResultName
"C:\Temp\Res_01"
ResultCleanN
Results name. For example, "Res_01"
ame
ResultLocatio
Results directory. For example, "C:\Temp"
n
Note: ResultName (full path) = ResultLocation (directory) + ResultCleanName
(name)

Well, let's see different variants of how to open and run LoadRunner Controller
script:

Open LoadRunner Controller:


Wlrun.exe

Open LoadRunner Controller scenario 'scenario.lrs' and do not execute it:


Wlrun.exe -TestPath scenario.lrs

Open LoadRunner Controller scenario 'scenario.lrs', execute it, and save


results to default folder ('C:\Documents and Settings\user_login\Local
Settings\Temp\res'):
Wlrun.exe -Run -TestPath scenario.lrs

Open LoadRunner Controller scenario 'scenario.lrs', execute it, and save


results to 'res_folder' folder:
Wlrun.exe -Run -TestPath scenario.lrs -ResultName res_folder

Open LoadRunner Controller scenario 'scenario.lrs', execute it, save results to


'res_folder' folder, and after that start Analysis on created results with default
template:
Wlrun.exe -Run -TestPath scenario.lrs -ResultName res_folder
-InvokeAnalysis

And please see more complex example for desert :)

Open LoadRunner Controller scenario 'scenario.lrs', execute it, save results to


'res_folder' folder, and after that start Analysis on created results with default
template. Repeat all these steps 10 times:
set LR_HOME=C:\Program Files\Mercury\LoadRunner
for /L %%i in (1,1,10) do "%LR_HOME%\bin\Wlrun.exe" -Run
-TestPath "%LR_HOME%\scenario\memory_leak_crash.lrs" -ResultName
C:\Temp\LR_Res\result%%i
Result is:

Well, where to use execution from a command line?


It can be very useful in some cases, when you plain to:

• run LoadRunner Controller and pass its results to LoadRunner Analysis


• run LoadRunner scripts by schedule

7. Recording A File Saving in Load Runner

The problem:
This is a frequently asked question - why file downloading from a browser page
(right mouse click, then "Save Target As...") was not recorded in LoadRunner
VuGen script?

The difference between functional and load testing:


Actually, LoadRunner records a file transferring only, not downloading!
This is the principal difference between functional and load testing! I will
describe it.

Functional testing is done from a user's viewpoint.


What does a user see? It sees windows, dialogs, UI cotrols.
For example, user can see downloaded html-page in a browser, or as plain text in
a telnet session.
In this case, data transferring is the same (HTTP protocol), while data
representation varies (browser or telnet session).

LoadRunner performs Load testing, i.e. it records and emulates data


transferring between client and server. Data transferring only, not data
displaying for user!
For the above example, html-page can be downloaded directly from web-server.
Another variant - page can be downloaded from FTP-server (even using Secured
FTP protocol - FTPS), and then data will be passed to browser. User will see the
same page.
In this case, data representation is the same (browser page), while data
transferring varies (HTTP or FTPS protocols).

So, remember the simple rule:

LoadRunner does not record client side activities!


Tips: That's why LoadRunner does not show browser windows during load
testing.
Note: Please, do not tell me, that VuGen shows Run-Time Viewer during
replay :)
The run-time viewer was developed specifically for script debugging. There is no
dependency between data representations in Run-Time Viewer and in a real
browser (for detailed info read Mercury Support Knowledge Base (http://kb-
web.mercury.com, requires login), topic 14094 "What are the limitations of the
Run-Time Viewer").

And that's why it is impossible to record a mentioned file downloading (right


mouse click, then menu item "Save Target As...") . The answer is simple - this is
not a load testing :)
To perform this action, use functional testing tools - QTP, SilkTest, Selenium, and
others.

7. Down load file from server and save it to disk

In my previous article, "How to record a file saving, performed by user from


browser page?", I shown that user's activities are not recorded by LoadRunner.
This is a rule!

LoadRunner records file transferring from server and does not record file
saving.

What to do, if you have to save transferred file to local disk?


Continue reading, and you will get the solution :)
So, Let's start.
You can download file from a server with the web_url function.
See an example:
Image downloading:

1. web_url("logo.gif",
2. "URL=http://www.google.com/intl/en_ALL/images/logo.gif",
3. "Resource=1",
4. "RecContentType=image/gif",
5. "Snapshot=t1.inf",
6. LAST);

This code downloads Google's logo image:

To save this image as file to local disk, we have to perform these steps:

1. Capture image from server's response


2. Save captured data to local disk

How to capture image from server's response?

Use web_reg_save_param function with the following boundaries -


"LB=\r\n\r\n", "RB=". These boundaries allows to capture the whole data from a
body of server's response. Function will look like:
web_reg_save_param("prmLogoImage", "LB=\r\n\r\n", "RB=", LAST);

This function should be placed before web_url function. After execution,


prmLogoImage parameter will contain GIF-file.

I will clarify briefly the meaning of boundaries - "LB=\r\n\r\n" and "RB=".


Please, read the basic concepts of HTTP protocol, read Request message section:

HTTP response consists of the following:

• Headers, such as HTTP/1.1 200 OK or Content-Length: 3473


• An empty line
• A message body, containg text of requested page or file

So, Header and Message body should be separated by empty line.


First CRLF (that is, a carriage return (CR = "\r") followed by a line feed (LF =
"\n")) ends last header, and second CRLF ( = "\r\n") creates empty line. All data,
followed by second CRLF, are treated as message body.
To summurize - "LB=\r\n\r\n" says "start capturing from the beginning of
message body", empty right boundary "RB=" says "capture data till the end of
message".

Open LoadRunner and enable logging of data, returned by server:

Then execute script containing initial web_url function, and open Replay log:

As you see, Replay log


contains "\r\n\r\n" at the end of server's response.
Also, pay attention, that server returns the length of file to be downloaded
(Content-Length: 8558).

Save captured data to local disk


Saving captured binary data (in our case, GIF file) requires additional step - we
have to determine the length (= size) of captured data.

Tips: The simplest way - strlen function - is not correct. Imagine, that that
captured data contains embedded NULL characters ('\0'):
"123\0qwe"
The real size of captured data = 7 bytes ('1', '2', '3', '\0', 'q', 'w', 'e').
But strlen function will return value 3, because it counts bytes before the first
NULL character ('\0').

To calculate size of captured data use lr_eval_string_ext function:


lr_eval_string_ext ("{prmLogoImage}", strlen("{prmLogoImage}") /* = 14*/,
&szBuf, &nLength, 0, 0,-1);

lr_eval_string_ext function copies captured data into szBuf array and places a
size of captured data into nLength variable. That's easy, I hope :) If not, Help will
help :)

Tips: There is another way to get known the size of file to be downloaded.
Remember, that server returned the length of file (Content-Length: 8558). So,
you can extract this value using Correlation.

And the last action is to save binary data from szBuf array into a local file. I used
standard fwrite function from C programming language:
fwrite(szBuf, len, 1, hFile);

Well, please see the whole source code:


Click the block to expand the source code:

1. int WriteDataToFile(char *szFileName, const char *szBuf,


int len)
2. {
3. int hFile;
4.
5. hFile = fopen(szFileName,"wb");
6. .....

Execute the source code, and you will see, that new file will be created and
saved automatically - "C:\LogoImage.gif". And this is what we needed -
Google's logo image.