An Alternative for Mercury Virtual Table Server

3 April, 2008 – 4:10 pm

Mercury’s Virtual Table Server (VTS) provides the following functionality when sharing data between vusers in your typical LoadRunner scenario …

Virtual Table Server (VTS) first edition, introduced the capability for LoadRunner virtual users, WinRunner and XRunner, to communicate in real time. Data extraction and communication was simplified but limited to column/queue level operations. The new Virtual Table Server II provides a higher degree of data manipulation and 5-10 times better performance. From row level queries, retrievals, updates, insertions, unqueue entries, to database access, VTS II provides the functionality and ease for enhanced inter-process, inter-virtual user communication

A useful tool in itself, but with some annoying limitations. MyLoadTest elaborates on this:

The API is simple, but unfortunately does not allow you to write SQL queries; instead you must use the functions provided, like lrvtc_retrieve_row() and lrvtc_query_row()…

Read on for an alternative when using web vusers in LoadRunner.

Using WAMP (Windows, Apache, MySql & PHP) I came up with a simple alternative called VTSFaker. The concept relies on the use of web_reg_save parameters obtained from a simple web_url call to a ‘central’ WAMP server. I say central in the sense you might have n load generators in your environment all sharing the single WAMP server.

In the LoadRunner script I have abstracted the call to the WAMP server using a custom dbApi() action which you can load in your vuser_init or include as a custom header.

In its simplest form, if you wanted to parametize a value called ‘advertiserId’, you simply need to call the dbApi function as follows:
dbApi("selectUniqueOnce", "advertiserId", "advertisers","","");

The purpose of the dbApi action is to call a web page hosted by your WAMP installation using query based parameters as follows:
http://d112295/VTSFaker/api.php?method=selectUniqueNext&column=advertiserId&table=advertisers&vuser=None_-1_0&value=&where=

This in turn returns a formatted page with the result in a custom tag. LoadRunner then parametizes that result using a web_reg_save_param function call as follows:
web_reg_save_param(column,"LB=<span id=result>","RB=</span>","Search=Body","Notfound=warning",LAST);

All of this logic is abstracted in the dbApi action itself which hopefully simplifies the whole process.

In the background, I’ve created a simple API using PHP accessed via a webpage that makes calls to your MySql database. I think you get the picture … BTW, if you’re worried about performance, I did some preliminary tests on a 2GB RAM machine with the load generator and WAMP installation collocated with up to 600 concurrent vusers with no problems. Provided you index your MySql tables properly, result sets are returned in milliseconds, with not much fuss at all. In any case I’ve added an lr_start/end transaction statement to each API call, so that you could if necessary, subtract those average response times from your measured transactions if WAMP performance was degraded during your test run…

To get this all working follow the steps below:

1. Setup a WAMP installation. I’m using WAMPSERVER v2.0 which can be obtained for free at http://www.wampserver.com

2. Setup your database tables; I’m assuming you know how to drive MySql. Here’s an example table I’m using at present:

CREATE TABLE `advertisers` (
  `id` int(4) NOT NULL auto_increment,
  `advertiserId` varchar(64) default NULL,
  `productId` varchar(64) default NULL,
  `hasArtwork` tinyint(4) default NULL,
  `vuserId` varchar(128) default NULL,
  `update` timestamp NULL default NULL on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`),
  KEY `advertiserId_idx` (`advertiserId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Note: the mandatory use of an id column (to help sort result sets) and a vuserId column (to provide unique result sets). The others are optional depending on what data you want to retrieve/store.

3. Setup your VTSFaker aliased website on WAMP (Apache -> Alias Directories -> Add an alias -> VTSFaker) using the example PHP files here.

4. Add to your vuser_init or custom header the dbApi action using the example code below.

/*  ---------------------------------------------------------------------  
  Custom DB API for MySql
 
  Support for the following methods:
    selectUniqueOnce -  select a new row that is unique for this vuser
              and re-use row for entire scenario.
    selectUniqueNext -  select next available row that is unique for
              this vuser for entire scenario.
    updateColumn   -  Update a column based on where clause
 
  Examples:
    char where[256];
 
    dbApi("selectUniqueOnce",     // method
        "advertiserId",       // column
        "advertisers","","");    // table
                  
    dbApi("selectUniqueNext",     // method
        "advertiserId",       // column
        "advertisers","","");   // table
    
    strcpy(where, "");
    strcat(where, "advertiserId=");
    strcat(where, lr_eval_string("{advertiserId}") );
  
    dbApi("updateColumn",      // method
        "productId",         // column
        "advertisers",      // table
        "123456",          // value
        where);           // where
  ------------------------------------------------------------------– */
dbApi(char* method, char* column, char* table, char* value, char* where)
{
    // vars
  int debug = 1;
  int vuserId, scenarioId;
  int httpRC;
    char *vuserGroup;
    char vuser[128];
  char buff[20];
    char url[256];
 
    // enum vuser
    lr_whoami(&vuserId, &vuserGroup, &scenarioId);
    if(debug>0) lr_message( "Group: %s, vuser id: %d, scenario id %d", vuserGroup, vuserId, scenarioId);
  strcpy(vuser, "");
    strcat(vuser, vuserGroup);
  sprintf(buff, "_%i", vuserId);
  strcat(vuser, buff);
  sprintf(buff, "_%i", scenarioId);
  strcat(vuser, buff);
      
    // build url
    strcpy(url,"URL=http://VTSFaker/VTSFaker/api.php?method=");
    strcat(url,method);
    strcat(url,"&column=");
    strcat(url,column);
    strcat(url,"&table=");
    strcat(url,table);
  strcat(url,"&vuser=");
    strcat(url,vuser);
  strcat(url,"&value=");
  strcat(url,value);
  strcat(url,"&where=");
  strcat(url,where);
  if(debug>0) lr_message("dbAPI URL: %s", url);
 
    // get results
  if (strncmp(method, "select", 6) == 0) {
    web_reg_save_param(column,"LB=<span id=result>","RB=</span>","Search=Body","Notfound=warning",LAST);
  }
  lr_start_transaction("dbApi");
  web_url("api.php",
     url,
     "Resource=0",
     "RecContentType=text/html",
     "Referer=",
     "Snapshot=t69.inf",
     "Mode=HTML",
     LAST);
  lr_end_transaction("dbApi", LR_AUTO);
 
    // enum errors
  httpRC = web_get_int_property(HTTP_INFO_RETURN_CODE);
    if (httpRC != 200){
      if (httpRC < 200){
        lr_error_message("Error: HTTP Return Code %", httpRC);
      }
      else {
        lr_error_message("Error: HTTP Return Code %i", httpRC);
      }
      return 1;
   }
   return 0;
}

Enjoy
:)

Share it: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Netscape
  • Reddit
  • Slashdot
  • Technorati
  • YahooMyWeb

Post a Comment

*
To prove that you're not a bot, enter this code
Anti-Spam Image