LR Methods

LoadRunner Script Methods - Quick View

I’m going to compile a few ideas here that I find useful for developing quick script solutions, particularly for my newer CI approaches.

This page may be a bit messy and you may need to search for various terms to find the code you are after. This is just a notepad for my use.

Some top level functions that are useful - bas64 encoding etc.:

For random to work properly (I tested it!), you need to seed just once per user. So I put the seed in vuser_init() and each call to rand() will use that seed:

   srand( time(NULL) );

Functions:

void strRnd(int length, char* field)
{
    char possible[30] = "abcdef ghijklmn opqrstuv wxyz";
    int i,irnd;
    
    //For LoadRunner, need to add on Value= at the beginning. Watch out - these are now just for posting:
    sprintf(field,"Value=");
    for (i=0; i < length; i++ )
    {
        irnd = rand() % 29;
        //lr_message("%d",irnd);
        strncat(field,possible+irnd,1);
        //lr_message(field);
    }
}

int isSubstring(char * haystack, char * needle) 
{
     int i = 0;
     int d = 0;
     
     if (strlen(haystack) >= strlen(needle)) 
     {
         for (i = strlen(haystack) - strlen(needle); i >= 0; i--) 
         {
             int found = 1; //assume we found (wanted to use boolean)
             for (d = 0; d < strlen(needle); d++) 
             {
                 if (haystack[i + d] != needle[d]) 
                 {
                     found = 0; 
                     break;
                 }
             }
             if (found == 1) 
             {
                 return i;
             }
         }
         return -1;
         
     } 
     else 
     {
         //fprintf(stdout, "haystack smaller\n"); 
         return -2;
     }
 } 

/*
Base 64 Encode and Decode functions for LoadRunner
==================================================
This include file provides functions to Encode and Decode
LoadRunner variables. It's based on source codes found on the
internet and has been modified to work in LoadRunner.
 
Created by Kim Sandell / Celarius - www.celarius.com


EXAMPLE USE:
#include "base64.h"
vuser_init()
{
 int res;
 // ENCODE
 lr_save_string("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789","plain");
 b64_encode_string( lr_eval_string("{plain}"), "b64str" );
 lr_output_message("Encoded: %s", lr_eval_string("{b64str}") );
 
 // DECODE
 b64_decode_string( lr_eval_string("{b64str}"), "plain2" );
 lr_output_message("Decoded: %s", lr_eval_string("{plain2}") );
 
 // Verify decoded matches original plain text
 res = strcmp( lr_eval_string("{plain}"), lr_eval_string("{plain2}") );
 if (res==0) lr_output_message("Decoded matches original plain text");
 
 return 0;
}
*/
// Encoding lookup table
char base64encode_lut[] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q',
'R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h',
'i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y',
'z','0','1','2','3','4','5','6','7','8','9','+','/','='};
 
// Decode lookup table
char base64decode_lut[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,62, 0, 0, 0,63,52,53,54,55,56,57,58,59,60,61, 0, 0,
0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25, 0, 0, 0, 0, 0, 0,26,27,28,
29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
49,50,51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
 
void base64encode(char *src, char *dest, int len)
// Encodes a buffer to base64
{
 int i=0, slen=strlen(src);
 for(i=0;i<slen && i<len;i+=3,src+=3)
 { // Enc next 4 characters
 *(dest++)=base64encode_lut[(*src&0xFC)>>0x2];
 *(dest++)=base64encode_lut[(*src&0x3)<<0x4|(*(src+1)&0xF0)>>0x4];
 *(dest++)=((i+1)<slen)?base64encode_lut[(*(src+1)&0xF)<<0x2|(*(src+2)&0xC0)>>0x6]:'=';
 *(dest++)=((i+2)<slen)?base64encode_lut[*(src+2)&0x3F]:'=';
 }
 *dest='\0'; // Append terminator
}
 
void base64decode(char *src, char *dest, int len)
// Encodes a buffer to base64
{
 int i=0, slen=strlen(src);
 for(i=0;i<slen&&i<len;i+=4,src+=4)
 { // Store next 4 chars in vars for faster access
 char c1=base64decode_lut[*src], c2=base64decode_lut[*(src+1)], c3=base64decode_lut[*(src+2)], c4=base64decode_lut[*(src+3)];
 // Decode to 3 chars
 *(dest++)=(c1&0x3F)<<0x2|(c2&0x30)>>0x4;
 *(dest++)=(c3!=64)?((c2&0xF)<<0x4|(c3&0x3C)>>0x2):'\0';
 *(dest++)=(c4!=64)?((c3&0x3)<<0x6|c4&0x3F):'\0';
 }
 *dest='\0'; // Append terminator
}
 
int b64_encode_string( char *source, char *lrvar )
// ----------------------------------------------------------------------------
// Encodes a string to base64 format
//
// Parameters:
//        source    Pointer to source string to encode
//        lrvar     LR variable where base64 encoded string is stored
//
// Example:
//
//        b64_encode_string( "Encode Me!", "b64" )
// ----------------------------------------------------------------------------
{
 int dest_size;
 int res;
 char *dest;
 // Allocate dest buffer
 dest_size = 1 + ((strlen(source)+2)/3*4);
 dest = (char *)malloc(dest_size);
 memset(dest,0,dest_size);
 // Encode & Save
 base64encode(source, dest, dest_size);
 lr_save_string( dest, lrvar );
 // Free dest buffer
 res = strlen(dest);
 free(dest);
 // Return length of dest string
 return res;
}
 
int b64_decode_string( char *source, char *lrvar )
// ----------------------------------------------------------------------------
// Decodes a base64 string to plaintext
//
// Parameters:
//        source    Pointer to source base64 encoded string
//        lrvar     LR variable where decoded string is stored
//
// Example:
//
//        b64_decode_string( lr_eval_string("{b64}"), "Plain" )
// ----------------------------------------------------------------------------
{
 int dest_size;
 int res;
 char *dest;
 // Allocate dest buffer
 dest_size = strlen(source);
 dest = (char *)malloc(dest_size);
 memset(dest,0,dest_size);
 // Encode & Save
 base64decode(source, dest, dest_size);
 lr_save_string( dest, lrvar );
 // Free dest buffer
 res = strlen(dest);
 free(dest);
 // Return length of dest string
 return res;
}

A few Time codes and header tracers to identify requests in the log files

    for(i=0;i<2048;i++)
    {
        strtemp1[i] = '\0';
        newEndPoint[i] = '\0';
    }
    
    for(i=0;i<56;i++)
        strdate[i] = '\0';
    
    if(strlen(lr_eval_string("{endpoint}")) == 0)
    {
        lr_log_message("zero length endpoint");
        return 0;
    }
    
    web_add_auto_header("X-Cx-Feed-Key","Son2iekuaSixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5Aigae1pu");
    
    _tzset(); // Sets variables used by localtime 
    
    web_set_max_html_param_len("2048");
    
    lr_whoami(&id, &vuser_group, &scid);
    if(id < 0)
        id = 1;
    lr_message( "Group: %s, vuser id: %d, scenario id %d", vuser_group, id, scid);
    
    iteration++;
    t = time64(0);
    
    //sprintf(ending,"_=(uid:%d;%%20tid:%d;%%20did:prftst-%s)",id,iteration,local_ip);
    sprintf(ending,"_=(uid:%d; tid:%d; did:prftst-%s)",id,iteration,local_ip);
    lr_log_message("ending: %s",ending);

    sprintf(userAgent,"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT)%s",ending);
    //sprintf(userAgent,"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT)");
    web_add_auto_header("User-Agent",userAgent);
    
    //sprintf(ending,"_=(uid:%d;%%20tid:%d;%%20did:prftst-%s)_%d",id,iteration,local_ip,t);
    sprintf(ending,"_=(uid:%d; tid:%d; did:prftst-%s)_%d",id,iteration,local_ip,t);
    lr_log_message("ending: %s",ending);
            
      //lr_output_message("strtemp1 (top0): %s",strtemp1);
    strcpy(strtemp1,lr_eval_string("{endpoint}"));
    //lr_output_message("strtemp1 (top): %s",strtemp1);

 

Local ip function. Useful for logging injectors in use into the LR summary - really useful for CI

log_local_ip()
{
    //USE THIS FUNCTION IN PROJECT SCRIPTS TO LOG LOCAL IP OF INJECTOR
    //Useful for showing which/how many injectors we are using
    
     long fp; // file/stream pointer
    int count; // number of characters that have been read from the stream.
    char buffer[BUFFER_SIZE]; // allocate memory for the output of the command.
    char * token;
    char param_buf[10]; // buffer to hold the parameter name.
    int i,k,j,len,gotfirstdot,gotfirstnum;
    char strtemp[256];
    int rc;
    
    /* this function taken from:
    http://www.myloadtest.com/dos-commands-from-loadrunner/
    */
   
    /*
     * Running a command, and splitting the output into separate parameters for each element.
     */ 
 
    // "DIR /B" gives a "bare" directory listing (in this case, of the files in the VuGen script directory).
    //fp = popen("DIR /B", "r");
    
    //get the ip address of the injector
    fp = popen("ipconfig", "r"); /* my own bit! */
    
    if (fp == NULL) {
        lr_error_message("Error opening stream.");
        return -1;
    }
 
    count = fread(buffer, sizeof(char), BUFFER_SIZE, fp); // read up to 10KB
    if (feof(fp) == 0) {
        lr_error_message("Did not reach the end of the input stream when reading. Try increasing BUFFER_SIZE.");
        return -1;
    }
    if (ferror(fp)) {
        lr_error_message ("I/O error during read."); 
        return -1;
    }
    buffer[count] = NULL;
 
    // Split the stream at each newline character, and save them to a parameter array.
    token = (char*) strtok(buffer, "\n"); // Get the first token 
 
    if (token == NULL) { 
        lr_error_message ("No tokens found in string!"); 
        return -1; 
    }
 
    i = 1;
    while (token != NULL) { // While valid tokens are returned 
        sprintf(param_buf, "output_%d", i);
        lr_save_string(token, param_buf);
        i++;
        token = (char*) strtok(NULL, "\n"); 
    }
    lr_save_int(i-1, "output_count");
 
    // Print all values of the parameter array.
    for (i=1; i<=lr_paramarr_len("output"); i++) {
        lr_output_message("Parameter value: %s", lr_paramarr_idx("output", i));
        
        if(strstr(lr_paramarr_idx("output", i),"IPv4 Address"))
        {
            strcpy(strtemp,lr_paramarr_idx("output", i));
            len = strlen(strtemp);
            gotfirstdot=0;
            gotfirstnum=0;
            for(k=0,j=0;k<len;k++)
            {
                if(strtemp[k] == '.')
                    gotfirstdot=1;
                
                if(gotfirstdot)
                {
                    if(strtemp[k] >= '0' && strtemp[k] <= '9')
                    {
                        gotfirstnum=1;
                        local_ip[j] = strtemp[k];
                        j++;
                    }
                    else if(gotfirstnum && strtemp[k] == '.')
                    {
                        local_ip[j] = '-';
                        j++;
                    }
                }
            }
            lr_output_message("local_ip: %s",local_ip);
            
            sprintf(strtemp,"Using injector %s",local_ip);
            lr_set_transaction(strtemp,0.01,LR_PASS); /* my own bit! */
        }
    }
 
    pclose(fp);
   
    return 0;    
}

 

Using one script for a full model

This makes it easier to ramp up users, especially with CI setups

If you have separate data files for each transaction type:

 

irnd = rand() % 100;
if (irnd < 46)
   sprintf(nextPage, "brands");
else if (irnd < 75)
   sprintf(nextPage, "episode_guide");
else if (irnd < 88)
   sprintf(nextPage, "video");
else if (irnd < 95)
   sprintf(nextPage, "articles");
else if (irnd < 98)
   sprintf(nextPage, "categories");
else if (irnd < 99)
   sprintf(nextPage, "atoz");
else
   sprintf(nextPage, "pictures");

Then lower down:

 

if(strcmp(nextPage,"brands") == 0 )
{
   lr_start_transaction("brands");

   web_url("brands",
   "URL=http://bips.{environment}.chan.com{brands}",
   "Resource=0",
   "RecContentType=text/html",
   "Referer=https://id.{environment}.chan.com/login?redirectUrl=https://xxx.{environment}.chan.com/http/why-register/",
   "Snapshot=t5.inf",
   "Mode=HTML",
   LAST);

   lr_end_transaction("brands",LR_AUTO);
}
else if(strcmp(nextPage,"episode_guide") == 0 )

OR, put your data in an array and then use a similar method to above to add a selection curve by setting array indexes, maybe with a second (small) random:

//Note: episodeIds are stored in the ‘endpoint’ parameter historically in this case:

    sprintf(firstItem,lr_eval_string("{endpoint}"));
    
    lr_log_message("firstItem at top = %s", firstItem);

    lr_continue_on_error(LR_ON_ERROR_CONTINUE); //don't stop when you get a 404
    
    i=0;
    do
    {
        sprintf(episodeIdArray[i], lr_eval_string("{endpoint}"));        
        lr_log_message("firstItem at bottom = %s. episodeId param = %s, i = %d", firstItem,episodeIdArray[i], i);
                
        lr_advance_param("endpoint");
        i++;
        
        if(i == 10000)
            break;
    }
    while(strcmp(lr_eval_string("{endpoint}"),firstItem) != 0);
    
    num_episodeIds = i;
    lr_log_message("num episodeIds = %d, Last one = %s", num_episodeIds,lr_eval_string("{endpoint}"));    
    

 

And need this often when using SSL at one place I was based at:

web_set_sockets_option("SSL_VERSION","TLS");

Debug on/off with code - Good for targeted results traces - easier than getting full debug stack

//lr_set_debug_message(LR_MSG_CLASS_EXTENDED_LOG | LR_MSG_CLASS_RESULT_DATA | LR_MSG_CLASS_FULL_TRACE, LR_SWITCH_ON );

lr_set_debug_message(LR_MSG_CLASS_EXTENDED_LOG | LR_MSG_CLASS_RESULT_DATA | LR_MSG_CLASS_FULL_TRACE, LR_SWITCH_OFF );

 

Save a cookie - sometimes tricky - use headers here

web_reg_save_param_ex("ParamName=C_Identity","LB=C_Identity=","RB=;",SEARCH_FILTERS,"Scope=Headers",LAST);

 

lr_message("C_Identity=%s",lr_eval_string("{C_Identity}"));

 

Then set this cookie to use for another domain (in my case):

web_add_cookie("C_Identity={C_Identity}; domain={environment2}");

Get return code or download size to determine pass/fail - useful for CI especially

int HttpRetCode;
int HttpSize;

HttpRetCode = web_get_int_property(HTTP_INFO_RETURN_CODE);

if (HttpRetCode == 200 || HttpRetCode == 201) //special code for my app
{
    lr_log_message("Code: %d", HttpRetCode);
   //rc = lrvtc_send_message("app1_URL200", newEndPoint);
}

HttpSize = web_get_int_property(HTTP_INFO_DOWNLOAD_SIZE);

lr_log_message("d_size: %d",HttpSize);

web_reg_save_param can be set to ignore items not found and to get all findings into an array:

web_reg_save_param_ex("ParamName=accessToken","LB=\"accessToken\":\"","RB=\"","Notfound=warning",LAST);

OR

web_reg_save_param("programmeId", "LB=\"programmeId\":\"","RB=\"","Notfound=warning","Ord=All",LAST);

TotalNumberOfMatches=atoi(lr_eval_string("{programmeId_count}"));

if(TotalNumberOfMatches > 0)
{

   lr_log_message("programmeId = %s",lr_eval_string("{programmeId_1}"));

   ....

}

Fail a page if an error page is shown - good for CI, especially when a CDN caches pages

web_reg_find("Text=Page Not Found","Fail=Found",LAST);
web_reg_find("Text/IC=error.css","Fail=Found",LAST);

 

 

 

 

 

 

[Home] [About (CV)] [Contact Us] [JMeter Cloud] [webPageTest] [_64 images] [asset moniitor] [Linux Monitor] [Splunk ETL] [Splunk API] [AWS bash] [LR Rules OK] [LR Slave] [LR CI Graphs] [LoadRunner CI] [LR CI Variables] [LR Bamboo] [LR Methods] [LR CI BASH] [Bash methods] [Jenkins V2] [Streaming vid] [How fast] [Finding Issues] [Reporting] [Hand over] [VB Scripts] [JMeter tips] [JMeter RAW] [Dynatrace] [Documents] [FAQ] [Legal]

In the Cartesian Elements Ltd group of companies