Showing posts with label vugen. Show all posts
Showing posts with label vugen. Show all posts

Monday, December 10, 2012

Loadrunner How to Download an Image

Usually images such as jpg, gif, png, etc., will be downloaded automatically as extra resources.  However, occasionally it is necessary to download images directly.  Downloading an image directly can be done easily as follows:
  • make web_url call requesting jpg, gif, png, etc.
  • Set Resource=1 indicating the the downloaded item is a resource
  • Use content type/mime type "image/jpg", "image/gif", "image/png", etc.
The following script illustrates this method as follows:
  • Image of type png is downloaded
  • Downloaded image file size is retrieved and checked that it is as expected.
  • Script writes an error message is the downloaded size is not as expected.

Script


Action()
{
long imgSize=0;

web_url("test pdf download",    
"URL=http://www.google.com/images/nav_logo114.png",
"Resource=1",
"RecContentType=image/png",
"Snapshot=t1.inf",
LAST);

    // Save pdf file size
imgSize = web_get_int_property(HTTP_INFO_DOWNLOAD_SIZE);

// Verify size is as expected (~28765 bytes 321 header bytes)
if (imgSize < 28765 ) {
lr_error_message("File download error, expected ~247,800 bytes but got %d", imgSize);
} else {
lr_output_message("File downloaded size okay, expected ~247,800 bytes and got %d", imgSize);
}

return 0;
}

Console Output


Running Vuser...
Starting iteration 1.
Starting action Action.
Action.c(6): web_url("test pdf download") was successful, 28765 body bytes, 321 header bytes   [MsgId: MMSG-26386]
Action.c(14): web_get_int_property was successful   [MsgId: MMSG-26392]
Action.c(20): File downloaded size okay, expected ~247,800 bytes and got 29086
Ending action Action.
Ending iteration 1.
Ending Vuser...

Wednesday, November 7, 2012

Loadrunner Logging Options

There are a number of different functions provided by Loadrunner for logging, including:

  • lr_message
  • lr_output_message
  • lr_error_message
  • lr_log_message
  • lr_debug_message
  • lr_vuser_status_message
This post provides a script illustrating each of these logging methods, and a description of the differences.

lr_message
The limitation of lr_message is that no source file (such as Action.c) or line number is provided.

lr_output_message
lr_output_message includes source file and line number information which is useful for debugging issues.

lr_error_message
lr_error_message flags the message as an error rather than informational.

lr_log_message
lr_log_message can reduce some network traffic during load tests by not sending messages to the load test output window.

lr_debug_message
lr_debug_message can write message conditionally on certain logging settings being enabled

lr_vuser_status_message
lr_vuser_status_message updates the vuser status field during load tests


The following script illustrates the various logging methods.

Script


Action()
{
// setup test message data
int msgLevel;
char *message = "This is a test message.";
        // save string to a parameter
        lr_save_string(message, "messageParam");

// lr_message test
lr_message("---------------------- lr_message --------------------------");
lr_message("--- lr_message does not show the source file and line number");
lr_message("--- lr_message: %s", message);
lr_message("----------------- end lr_message ---------------------");

// lr_output_message test
lr_message("------------------- lr_output_message -----------------------");
lr_message("--- lr_output_message does show the source file and line number");
lr_output_message("--- lr_output_message: %s", message);
lr_message("----------------- end lr_output_message ---------------------");

        // lr_error_message test
lr_message("------------------- lr_error_message -----------------------");
lr_message("--- lr_error_message writes a message with an Error log level");
lr_error_message("--- lr_error_message: %s", message);
lr_message("----------------- end lr_error_message ---------------------");

// lr_log_message test
lr_message("------------------- lr_log_message ------------------------");
lr_message("--- lr_log_message does not send messages to the output window and could therefore reduce network traffic between agent and load generator in some situations");
lr_log_message("--- lr_log_message: %s", message);
lr_message("----------------- end lr_log_message ---------------------");

// lr_debug_message test
lr_message("------------------- lr_debug_message -----------------------");
lr_message("--- lr_debug_message writes a message if the specified log settings are set");
    msgLevel=lr_get_debug_message();
if (msgLevel & LR_MSG_CLASS_BRIEF_LOG  ) {
lr_message("standard log is enabled");
} else if (msgLevel & LR_MSG_CLASS_EXTENDED_LOG  ) {
lr_message("extended log is enabled");
} else if (msgLevel & LR_MSG_CLASS_DISABLE_LOG  ) {
lr_message("log is disabled");


// log message if brief or extended log are enabled
lr_debug_message(LR_MSG_CLASS_BRIEF_LOG | LR_MSG_CLASS_EXTENDED_LOG, "--- lr_debug_message: %s", "This is written if brief or extended log is enabled");

// disable  brief and extended log
        lr_set_debug_message(LR_MSG_CLASS_BRIEF_LOG, LR_SWITCH_OFF); 
        lr_set_debug_message(LR_MSG_CLASS_EXTENDED_LOG, LR_SWITCH_OFF);

// now the debug message should not be written
lr_debug_message(LR_MSG_CLASS_BRIEF_LOG | LR_MSG_CLASS_EXTENDED_LOG, "This should not be written to log because brief and extended log are both disabled");

// re-enable extended log
        lr_set_debug_message(LR_MSG_CLASS_EXTENDED_LOG, LR_SWITCH_ON);

lr_message("----------------- end lr_debug_message ---------------------");

// lr_vuser_status_message
// lr_log_message test
lr_message("------------------- lr_vuser_status_message ------------------------");
lr_message("--- lr_vuser_status_message updates the status field of the vuser status area.  It does not write to the log");
lr_vuser_status_message("--- lr_vuser_status_message: %s", message);
lr_message("----------------- end lr_vuser_status_message ---------------------");

return 0;
}



Output

Running Vuser...
Starting iteration 1.
Starting action Action.
---------------------- lr_message --------------------------
--- lr_message does not show the source file and line number
--- lr_message: This is a test message.
----------------- end lr_message ---------------------
------------------- lr_output_message -----------------------
--- lr_output_message does show the source file and line number
Action.c(19): --- lr_output_message: This is a test message.
----------------- end lr_output_message ---------------------
------------------- lr_error_message -----------------------
--- lr_error_message writes a message with an Error log level
Action.c(25): Error: --- lr_error_message: This is a test message.
----------------- end lr_error_message ---------------------
------------------- lr_log_message ------------------------
--- lr_log_message does not send messages to the output window and could therefore reduce network traffic between agent and load generator in some situations
--- lr_log_message: This is a test message.
----------------- end lr_log_message ---------------------
------------------- lr_debug_message -----------------------
--- lr_debug_message writes a message if the specified log settings are set
extended log is enabled
--- lr_debug_message: This is written if brief or extended log is enabled
----------------- end lr_debug_message ---------------------
------------------- lr_vuser_status_message ------------------------
--- lr_vuser_status_message updates the status field of the vuser status area.  It does not write to the log
----------------- end lr_vuser_status_message ---------------------
Ending action Action.
Ending iteration 1.
Ending Vuser...
Starting action vuser_end.
Ending action vuser_end.
Vuser Terminated.

Friday, September 14, 2012

Loadrunner Convert To Unicode or UTF-8

The following shows how to convert strings in Vugen to unicode or UTF-8, which is necessary for certain applications with globalization functionality.

Script


Action() 

char *converted_buffer_unicode = NULL; 

// convert to unicode
lr_convert_string_encoding("Text to convert to unicode", 
LR_ENC_SYSTEM_LOCALE, 
LR_ENC_UNICODE, 
"paramUnicode"); 

// convert to UTF-8
lr_convert_string_encoding("Text to convert to utf8", 
LR_ENC_SYSTEM_LOCALE, 
LR_ENC_UTF8, 
"paramUtf8"); 

return 0; 




Console Output


Running Vuser...
Starting iteration 1.
Starting action Action.
Action.c(6): Notify: Saving Parameter "paramUnicode = T\x00e\x00x\x00t\x00 \x00t\x00o\x00 \x00c\x00o\x00n\x00v\x00e\x00r\x00t\x00 \x00t\x00o\x00 \x00u\x00n\x00i\x00c\x00o\x00d\x00e\x00\x00\x00".
Action.c(12): Notify: Saving Parameter "paramUtf8 = Text to convert to utf8\x00".
Ending action Action.
Ending iteration 1.

Thursday, September 13, 2012

Loadrunner Unique Names

It is useful to be able to create human-readable unique names to be used for filenames, database keys, logging, etc.  One way to do this is to create a string with the following information:

  • load generator name
  • vuser id
  • iteration number
  • timestamp
This can be done easily as follows:
  • get load generator name using lr_get_host_name()
  • get vuser id using lr_whoami()
  • get iteration number using a parameter of type iteration
  • get current timestamp using lr_save_datetime()
The following script shows how to do this.

Script

Action()
{
int id
char *host; 

        // get load generator name
host = lr_get_host_name( ); 
//lr_output_message("Host: %s", host);

// get vuser id
lr_whoami(&id, NULL, NULL);
//lr_message( "Vuser id: %d",  id);

        // for iteration add a parameter named "Iteration" of type Iteration
//lr_output_message(lr_eval_string("Iteration: {Iteration}")); 

        // get timestamp, formatted as wanted
        lr_save_datetime("%m-%d-%Y-%I%M%S%p", DATE_NOW, "now"); 
//lr_output_message(lr_eval_string("Time: {now}"));

        // now generate the nice, readable unique id
lr_output_message(lr_eval_string("Host-%s-VuserId-%d-Iteration-{Iteration}-Time-{now}"),host, id);

return 0;
}

Output
Action.c(20): Host-generator02-VuserId-1-Iteration-1-Time-09-13-2012-035856PM [MsgId: MMSG-17999]
Action.c(20): Host-generator02-VuserId-2-Iteration-1-Time-09-13-2012-035856PM [MsgId: MMSG-17999]
Action.c(20): Host-generator02-VuserId-1-Iteration-2-Time-09-13-2012-035857PM [MsgId: MMSG-
Action.c(20): Host-generator02-VuserId-2-Iteration-2-Time-09-13-2012-035857PM [MsgId: MMSG-17999
Action.c(20): Host-generator02-VuserId-1-Iteration-3-Time-09-13-2012-035858PM [MsgId: MMSG-17999]


Loadrunner Charting Custom Metrics

In Loadrunner, you can chart your own custom metrics easily by using the function lr_user_data_point.  These could include calls to the server to collect system stats, application metrics based on responses, or anything at all.  The custom metrics are then available in Loadrunner Analysis.  The following provides an example:

Script


double getMyMetric();

Action()
{
double mymetric;
int i;
for (i=0;i<100;i++) {

mymetric = getMyMetric(); 
lr_user_data_point("mymetric", mymetric); 
lr_log_message( "--- Added custom metric value = %f", mymetric );

return 0;
}


double getMyMetric()
{
    int randomInt = (rand() % 100)+1;  // Get a random number 1 - 100
double mymetric = randomInt / 100.0; // Return a double between 0  and 1
return mymetric;
}



Console Output


Running Vuser...
Starting iteration 1.
Starting action Action.
Action.c(10): Notify: Data Point "mymetric" value = 0.4800.
--- Added custom metric value = 0.480000
Action.c(10): Notify: Data Point "mymetric" value = 0.7900.
--- Added custom metric value = 0.790000
...


Analysis Output

The custom metric is then available in analysis:


A chart can be generated showing the trend of the custom data points added during the test:




Loadrunner Current Timestamp

In Vugen, it is helpful to include a datetime with log messages, either informational or errors.  This can be done very easily using the lr_save_datetime function.  The timestamp can also be formatted in many different ways using the format codes commented out in the script below.   The following script shows how this can be done:

Script


Action()
{
// handle an event such as an error or important message including a timestamp
lr_save_datetime("%m/%d/%Y %I:%M:%S %p", DATE_NOW, "now"); 
lr_output_message(lr_eval_string("{now}: My important message here.")); 

//  Format codes for lr_save_datetime
// %a  day of week, using locale's abbreviated weekday names
// %A  day of week, using locale's full weekday names
// %b  month, using locale's abbreviated month names
// %B  month, using locale's full month names
// %c  date and time as %x %X
// %d  day of month (01-31)
// %H  hour (00-23)
// %I  hour (00-12)
// %j  number of day in year (001-366)
// %m  month number (01-12)
// %M  minute (00-59)
// %p  locale's equivalent of AM or PM, whichever is appropriate
// %S  seconds (00-59)
// %U  week number of year (01-52), Sunday is the first day of the week. Week number 01 is the first week with four or more January days in it.
// %w  day of week; Sunday is day 0
// %W  week number of year (01-52), Monday is the first day of the week. Week number 01 is the first week with four or more January days in it.
// %x  date, using locale's date format
// %X  time, using locale's time format
// %y  year within century (00-99)
// %Y  year, including century (for example, 1988)
// %Z  time zone abbreviation
// %%  to include the "%" character in your output string

return 0;
}

Console Output


Running Vuser...
Starting iteration 1.
Starting action Action.
Action.c(29): 09/13/2012 02:56:41 PM: My important message here.
Ending action Action.
Ending iteration 1.

Monday, August 13, 2012

Recording Loadrunner Traffic in Fiddler

It can be useful to capture loadrunner http traffic in fiddler.  This can be useful, for example, for seeing the timeline of http requests, which ones are slow, what sort of parallelism exists, if any, etc.  It can also be useful to compare the vugen timeline of requests to the same information captured directly from the browser, as vugen may not match browser behavior as expected, by serializing what is sent asynchronously in parallel by the browser, etc.

Vugen can be configured in Runtime Settings, Internet Protocol, Proxy, Use Proxy Server, address=localhost, port=8888.
You then put breakpoints in the script before and after the section you want to record, run the script in vugen to the first breakpoint (with logging disabled), start capturing traffic in fiddler, run the script to the second breakpoint and stop capturing traffic in fiddler.  You can then see a visualization of the request pipeline in fiddler for your loadrunner traffic:
It is also a good idea to capture the traffic by running the script from the controller on the load generator to reduce vugen overhead.  You will get a more compact and realistic pipeline that way.

You can then record the same transaction manually using the web browser for comparison to loadrunner.



Thursday, July 5, 2012

LoadRunner Sub-Transactions

Often in a loadrunner script, many transactions are of a common type, like "save" or "search" or "report_view".  These common operations need to be aggregated for reporting purposes.  You want to easily create a chart showing, for example "Search Response Time" or "Searches Per Second" or "Search Response Time (percentile)".

One easy way to do this is to run the following perl script which will take any transaction and wrap it in a second "sub-transaction" of the name input.  For example, suppose you have the following in your Action.c:

lr_start_transaction("Search1");
...
lr_end_transaction("Search1", LR_AUTO);

...
...


lr_start_transaction("Search2");
...
lr_end_transaction("Search2", LR_AUTO);


Following running the script in the directory with your Action.c file, passing the parameter "search" ("perl lr-subtrans.pl search"), you would now have:


lr_start_transaction("Search1");
lr_start_transaction("search");
...
lr_end_transaction("search", LR_AUTO);
lr_end_transaction("Search1", LR_AUTO);
...
...

lr_start_transaction("Search2");
lr_start_transaction("search");
...
lr_end_transaction("search", LR_AUTO);
lr_end_transaction("Search2", LR_AUTO);


This would then allow very easy reporting of the aggregate search transaction.  After running the script, you have to go in and remove the sub-transactions around transactions that are not relevant, like perhaps "login", "homepage", "back", etc.


Script


#  lr-subtrans.pl
#  Loadrunner add subtransaction script
#
#
use File::Copy;

$transname = $ARGV[0];
$actionfile = "Action.c";
$backupfile = "Action.c.bak";
$outfile = "Action.c.subtrans.txt";

if ($transname eq "-?" or $transname eq "/?" or $transname eq "-help" or $transname eq "/help" or $transname eq "")
{
die "USAGE: perl lr-subtrans.pl <transactionName>     (Note: each transaction will be wrapped with a transaction named <transactionName>)\n";
}

copy($actionfile, $backupfile) or die "File cannot be copied.";


open (INFILE, $actionfile) or die "Can't open $actionfile";
open (OUTFILE, ">$outfile") or die "can't open $outfile";

while ($line = <INFILE>)
{
# Add server parameter and default check
if ($line =~ "lr_start_transaction")
{
print OUTFILE $line;
print OUTFILE "\tlr_start_transaction(\"$transname\"); \n";
}
# BIIT ID ("SESSION ID") RULE
elsif ($line =~ "lr_end_transaction")
{
print OUTFILE "\tlr_end_transaction(\"$transname\", LR_AUTO); \n";
print OUTFILE $line;
}
else 
{
print OUTFILE $line;
}
}
close (INFILE);
close (OUTFILE);

# Copy Action.c.correlated.txt to Action.c
copy($outfile, $actionfile) or die "Copy failed: $!";

Monday, March 12, 2012

How to Perform Mathematical Operations on Loadrunner Parameters

A simple way to perform calculations on parameters is as follows:

  • Convert the Loadrunner parameter to a C variable
  • Perform the calculation on the C variable
  • Push the C variable back to the parameter

The following shows how to do that in the case of addition and multiplication on a Loadrunner parameter.

Script

Action()
{
    // Assume you start with a parameter "{paramInt}"
    int i = 0;
    int result = 0;
    int num = 10; 
    lr_save_int(num, "paramInt"); 
    lr_log_message("Parameter value at start = %s", lr_eval_string( "{paramInt}" ));


    // Save the parameter to a C variable
    i = atoi( lr_eval_string( "{paramInt}" ));


    // Perform the calculation
    result = i + 10;
    
    // Save the calculation back to the parameter "{paramInt}"
    lr_save_int(result, "paramInt"); 
    lr_log_message("Parameter value after sample addition = %s", lr_eval_string( "{paramInt}" ));


    // Another example showing multiplication
    i = atoi( lr_eval_string( "{paramInt}" ));
    result = i * i;
    lr_save_int(result, "paramInt"); 
    lr_log_message("Parameter value after sample multiplication = %s", lr_eval_string( "{paramInt}" ));


    return 0;
}


Console Output

Running Vuser...
Starting iteration 1.
Starting action Action.
Parameter value at start = 10
Parameter value after sample addition = 20
Parameter value after sample multiplication = 400
Ending action Action.
Ending iteration 1.
Ending Vuser...

Thursday, February 2, 2012

How to Use Regular Expressions in Loadrunner Using Gnu Regex for Windows Library

The following describes how to use the Gnu Regex for Windows regular expression library with loadrunner.  The following summarizes the steps:

  • Download gnuwin32 Regex for Windows at  http://gnuwin32.sourceforge.net/packages/regex.htm
  • From gnuwin32 zip, copy regex.h to <loadrunner_install_directory>/include
  • In regex.h, comment out or remove the line  "#include <sys/types.h>" 
  • From gnuwin32 zip, copy regex2.dll to <loadrunner_install_directory>/bin
  • In the loadrunner script, load the regex2.dll
  • In the loadrunner script, compile the regular expression pattern
  • Call the regexec method with a string and the regular expression pattern
  • Check the return code for match or no-match

Simplest Example

/* 
 * Example of how to use gnuwin32 Regex with loadrunner
 * Download gnuwin32 Regex for Windows 2.7
 *   http://gnuwin32.sourceforge.net/packages/regex.htm
 * Comment out line "#include <sys/types.h>" from gnuwin32 regex.h
 * Put gnuwin32 regex.h in <loadrunner_install_directory>/include
 * Put gnuwin32 regex2.dll in <loadrunner_install_directory>/bin
 */
#include "regex.h" 


// preprocessor macros giving names to regex response codes
#define MATCH 0
#define NOMATCH 1
#define ERROR   2


int dll_loaded = 0;


Action()
{
  char *test_string = "test";
  char *pattern = ".est";
  regex_t pattern_buffer;
  int status;


  // load gnuwin32 regular expression dll if not already loaded
  if (!dll_loaded) 
  {
    lr_load_dll("regex2.dll"); 
  }


  // compile the regular expression pattern
  if (regcomp(&pattern_buffer, pattern, REG_EXTENDED)) // REG_EXTENDED = POSIX Extended Regular Expression syntax
  {
    lr_error_message("Failed to parse regex pattern: %s", pattern);
    return ERROR;
  }


  // see if the pattern matches the input string
  status = regexec(&pattern_buffer, test_string, 0, NULL, 0);  // For meaning of last 3 params, see api doc: http://gnuwin32.sourceforge.net/packages/regex.htm


  // log the results
  lr_log_message("%s string \"%s\" to regex pattern \"%s\"",
  status==MATCH ? "Matched" : "Failed to match",
  test_string,
  pattern);
}

Console Output

Running Vuser...
Starting iteration 1.
Starting action Action.
Matched string "test" to regex pattern ".est"
Ending action Action.
Ending iteration 1.
Ending Vuser...



Test Script
The following example runs through a list of tests of various regular expression patterns used with both match expected and no-match expected test cases.


/* 

 * Example of how to use gnuwin32 Regex with loadrunner
 * Download gnuwin32 Regex for Windows 2.7
 *   http://gnuwin32.sourceforge.net/packages/regex.htm
 * Comment out line "#include <sys/types.h>" from gnuwin32 regex.h
 * Put gnuwin32 regex.h in <loadrunner_install_directory>/include
 * Put gnuwin32 regex2.dll in <loadrunner_install_directory>/bin
 */
#include "regex.h" 


// preprocessor macros giving names to regex response codes
#define MATCH 0
#define NOMATCH 1
#define ERROR   2


int dll_loaded = 0;


Action()
{
  regex_t pattern_buffer;


  // load gnuwin32 regular expression dll if not already loaded
  if (!dll_loaded) 
  {
 lr_load_dll("regex2.dll"); 
  }


  // Run tests  expected to match
  RunTest("test", ".est", MATCH);  // regex any char operator
  RunTest("test", "a*test", MATCH); // regex zero or more operator
  RunTest("test", "t+est", MATCH); // regex one or more operator
  RunTest("tttest", "t{3}est", MATCH); // regex interval operator
  RunTest("test", "t(ES|es)t", MATCH); // regex alternation operator
  RunTest("test", "t[^abcdfghijklmnopqruvwxyz]*t", MATCH); // regex list operator, with negation and repetition
  RunTest("test", "[t-z]est", MATCH);  // regex range operator
  RunTest("test", "(([u-z]est)|([t-z]es[t-z]))", MATCH);  // regex grouping operator
  RunTest("tests", "^te.*", MATCH);  // regex beginning of line operator
  RunTest("tests", ".*s$", MATCH);  // regex end of line operator
// 
  // Run tests  expected to not match
  RunTest("test", ".test", NOMATCH);  // regex any char operator
  RunTest("est", "t+est", NOMATCH); // regex one or more operator
  RunTest("test", "t(ES|Es)t", NOMATCH); // regex alternation operator
  RunTest("test", "t[^abcdefghijklmnopqrsuvwxyz]*t", NOMATCH); // regex list operator, with negation and repetition
  RunTest("tes2t", "tes[:alpha:]*t", NOMATCH); // regex character class operator: alpha   // 
  RunTest("testA", "test[:digit:]", NOMATCH); // regex character class operator: digits
  RunTest("test", "[u-z]est", NOMATCH);  // regex range operator
  RunTest("test", "(([u-z]est)|([a-s]es[t-z]))", NOMATCH);  // regex grouping operator
  RunTest("tests", "^es.*", NOMATCH);  // regex beginning of line operator
  RunTest("tests", ".*t$", NOMATCH);  // regex end of line operator


  return 0;
}


/*
 *  RunTest
 *  input: test string to match to regex pattern
 *  input: regex pattern
 *  input: expected result: match or no matc
 */
void RunTest(char *test_string, char *pattern, int expectedResult)
{
int status = TestMatch(test_string, pattern);


// Report whether or not test passed
lr_log_message("%s %s string \"%s\" to regex pattern \"%s\"",
  expectedResult==status ? "TEST SUCCESS: As expected," : "TEST FAILURE: Not expected,",
  status==MATCH ? "matched" : "failed to match",
  test_string,
  pattern);
}


/*
 *  TestMatch
 *  input: test string to match to regex pattern
 *  input: regex pattern
 *  output results of match attempt
 */
int TestMatch(char *test_string, char *pattern)
{
regex_t pattern_buffer;
int status;


if (regcomp(&pattern_buffer, pattern, REG_EXTENDED)) // REG_EXTENDED = POSIX Extended Regular Expression syntax
{
lr_error_message("Failed to parse regex pattern: %s", pattern);
return ERROR;
}


    status = regexec(&pattern_buffer, test_string, 0, NULL, 0);  // For meaning of last 3 params, see api doc: http://gnuwin32.sourceforge.net/packages/regex.htm
return status;
}



Console Output


Running Vuser...
Starting iteration 1.


Starting action Action.
TEST SUCCESS: As expected, matched string "test" to regex pattern ".est"
TEST SUCCESS: As expected, matched string "test" to regex pattern "a*test"
TEST SUCCESS: As expected, matched string "test" to regex pattern "t+est"
TEST SUCCESS: As expected, matched string "tttest" to regex pattern "t{3}est"
TEST SUCCESS: As expected, matched string "test" to regex pattern "t(ES|es)t"
TEST SUCCESS: As expected, matched string "test" to regex pattern "t[^abcdfghijklmnopqruvwxyz]*t"
TEST SUCCESS: As expected, matched string "test" to regex pattern "[t-z]est"
TEST SUCCESS: As expected, matched string "test" to regex pattern "(([u-z]est)|([t-z]es[t-z]))"
TEST SUCCESS: As expected, matched string "tests" to regex pattern "^te.*"
TEST SUCCESS: As expected, matched string "tests" to regex pattern ".*s$"
TEST SUCCESS: As expected, failed to match string "test" to regex pattern ".test"
TEST SUCCESS: As expected, failed to match string "est" to regex pattern "t+est"
TEST SUCCESS: As expected, failed to match string "test" to regex pattern "t(ES|Es)t"
TEST SUCCESS: As expected, failed to match string "test" to regex pattern "t[^abcdefghijklmnopqrsuvwxyz]*t"
TEST SUCCESS: As expected, failed to match string "tes2t" to regex pattern "tes[:alpha:]*t"
TEST SUCCESS: As expected, failed to match string "testA" to regex pattern "test[:digit:]"
TEST SUCCESS: As expected, failed to match string "test" to regex pattern "[u-z]est"
TEST SUCCESS: As expected, failed to match string "test" to regex pattern "(([u-z]est)|([a-s]es[t-z]))"
TEST SUCCESS: As expected, failed to match string "tests" to regex pattern "^es.*"
TEST SUCCESS: As expected, failed to match string "tests" to regex pattern ".*t$"
Ending action Action.
Ending iteration 1.
Ending Vuser...


Wednesday, February 1, 2012

Loadrunner How To Read a File into a Parameter

Here is a method for reading the contents of a file into a loadrunner parameter.  This can be useful for various situations such as reading XML or JSON requests from file, reading data, etc.

Script



//#include <stdio.h>
#define SEEK_SET 0 /* beginning of file. */
#define SEEK_CUR 1 /* current position. */
#define SEEK_END 2   /* end of file */


Action()
{
long infile; // file pointer
char *buffer; // buffer to read file contents into
char *filename = "test.txt"; // file to read
int fileLen; // file size
int bytesRead; // bytes read from file
// 
// open the file
infile = fopen(filename, "rb");
if (!infile) {
  lr_error_message("Unable to open file %s", filename);
  return;
}


// get the file length
fseek(infile, 0, SEEK_END);
fileLen=ftell(infile);
fseek(infile, 0, SEEK_SET);
lr_log_message("File length is: %9d bytes.", fileLen);


// Allocate memory for buffer to read file
buffer=(char *)malloc(fileLen+1);
if (!buffer) {
  lr_error_message("Could not malloc %10d bytes", fileLen+1);
  fclose(infile);
  return;
}


// Read file contents into buffer
bytesRead = fread(buffer, 1, fileLen, infile);
if (bytesRead != fileLen) 
{
  lr_error_message("File length is %10d bytes but only read %10d bytes", fileLen, bytesRead);
}
else
{
  lr_log_message("Successfully read %9d bytes from file: ", bytesRead);
}
fclose(infile);


// Save the buffer to a loadrunner parameter
lr_save_var( buffer, bytesRead, 0, "fileDataParameter");
free(buffer);
lr_log_message("File contents: %s", lr_eval_string("{fileDataParameter}"));
}




Step by Step Walk Through
Constants needed for fseek calls, also available in stdio.h:

#define SEEK_SET 0 /* beginning of file. */
#define SEEK_CUR 1 /* current position. */
#define SEEK_END 2   /* end of file */


Open file:

infile = fopen(filename, "rb");
if (!infile) {
lr_error_message("Unable to open file %s", filename);
return;
}


Get file length:

        fseek(infile, 0, SEEK_END);
fileLen=ftell(infile);
fseek(infile, 0, SEEK_SET);
lr_log_message("File length is: %9d bytes.", fileLen);


Allocate memory to read file into:

buffer=(char *)malloc(fileLen+1);
if (!buffer) {
lr_error_message("Could not malloc %10d bytes", fileLen+1);
fclose(infile);
return;
}


Read file into memory:

bytesRead = fread(buffer, 1, fileLen, infile);
if (bytesRead != fileLen) 
{
lr_error_message("File length is %10d bytes but only read %10d bytes", fileLen, bytesRead);
}
else
{
lr_log_message("Successfully read %9d bytes from file: ", bytesRead);
}

Close file handle:
fclose(infile);


Save the file to a loadrunner parameter:

lr_save_var( buffer, bytesRead, 0, "fileDataParameter");
free(buffer);
        lr_log_message("File contents: %s", lr_eval_string("{fileDataParameter}"));


File
The following is an example input file "test.txt" which would be located in the script directory (<loadrunner installation directory>/scripts/<scriptname>/test.txt:


First line of file.
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><Node>Data</Node></soap:Body></soap:Envelope>
Last line of file


Console Output

Running Vuser...
Starting iteration 1.
Starting action Action.
File length is:       168 bytes.
Successfully read       168 bytes from file: 
File contents: First line of file.
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><Node>Data</Node></soap:Body></soap:Envelope>
Last line of file
Ending action Action.
Ending iteration 1.
Ending Vuser...