Thursday, December 1, 2011

How To Send Compressed XML Messages Using Loadrunner

This post describes one method to gzip XML requests prior to sending them to a web service from LoadRunner using the http protocol.  This method uses the following basic procedure:
  1. Load the zlib.dll which is included with LoadRunner.
  2. Use the gzwrite method in zlib.dll to write your xml request to a file
  3. Read the gzipped bytes into a char array
  4. Save the char array with the gzipped bytes to a parameter
  5. Set the request headers specifying compression
  6. Post the compressed request to the web service
The following script shows one example using this method:
int requestPrepared = 0;
Action()
{
typedef void *gzFile;
gzFile file;
long infile;
char *buffer;
        char *filename = "test.gz";
int count;
int fileLen;


// URL
        char *URL = (char *)"http://SERVER:8080/MyService";
        lr_save_string(URL, "URL_Param");


// .............. gzip request ..............
if ( !requestPrepared ) {
lr_load_dll("zlib.dll"); 
file = (void *)gzopen(filename, "wb");
count = strlen(lr_eval_string("{Request}"));
fileLen = gzwrite(file, lr_eval_string("{Request}"), count);
lr_log_message("Gzipped %9d bytes: ", fileLen);
gzclose(file);

// open the gzip 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);

// Allocate memory for buffer
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
count = fread(buffer, 1, fileLen, infile);
lr_log_message("Read %9d bytes from gzipped file: ", count);
fclose(infile);

// Save the buffer to a loadrunner parameter
lr_save_var( buffer, count, 0, "GZippedRequest");
free(buffer);
requestPrepared = 1;
}
// .............. end gzip request ..............


// Request Headers
web_add_header("Content-Type", "application/xml; charset=UTF-8");
web_add_header("Accept-Encoding", "gzip;q=1.0, identity; q=0.5, *;q=0");
web_add_header("Content-Encoding", "gzip");
        web_add_header("Cache-Control", "no-cache");
        web_add_header("Connection", "keep-alive");


// Validate response
web_reg_find("Text=<MyNode>MyValue</MyNode>", LAST);


lr_start_transaction("Post_request");


web_custom_request("Post_Request",
 "URL={URL_Param}",
 "Method=POST",
 "TargetFrame=",
 "Resource=0",
 "Referer=",
 "Mode=HTTP",
 "Body={GZippedRequest}",
 LAST); 


lr_end_transaction("Post_request", LR_AUTO);
}

Here is step-by-step walk-through:


  • Load the zlib.dll which is included with LoadRunner.  



  • lr_load_dll("zlib.dll"); 


  • Use the gzwrite method in zlib.dll to write your xml request to a file



  • file = (void *)gzopen(filename, "wb");
    count = strlen(lr_eval_string("{Request}"));
    fileLen = gzwrite(file, lr_eval_string("{Request}"), count);


  • Read the gzipped bytes into a char array



  • infile = fopen(filename, "rb"); 
    fileLen=ftell(infile); 
    buffer=(char *)malloc(fileLen+1); 
    count = fread(buffer, 1, fileLen, infile);


  • Save the char array with the gzipped bytes to a parameter



  • lr_save_var( buffer, count, 0, "GZippedRequest");


  • Set the request headers specifying compression



  • web_add_header("Accept-Encoding", "gzip;q=1.0, identity; q=0.5, *;q=0");
    web_add_header("Content-Encoding", "gzip");


  • Post the compressed request to the web service



  • web_custom_request("Post_Request", 
      "URL={URL_Param}",
      "Method=POST", 
      "TargetFrame=",
      "Resource=0",
      "Referer=",
      "Mode=HTTP",
      "Body={GZippedRequest}",
      LAST); 

    This technique could be varied in a number of ways.  One variation would be to parameterize the gzipped file's name per vuser, so that each vuser could send a different request as follows:
         // create parameter of type "Vuser ID" using format "file-vuser%03s.gz"
        char *filename = lr_eval_string("{filename}");

    Another variation would be to create a list of different parameterized requests up front in the init() section which could then be randomly sent in the Action() section.  With this method, you would not want to go to the file system on every iteration to vary request parameters unless the expected transaction rate is low, so you would want to create the gzipped requests once up front.


    4 comments:

    1. thanks. How do i set the compression level in this ?

      ReplyDelete
    2. This comment has been removed by the author.

      ReplyDelete
    3. I get an error for the typedef void *gfFile;
      Is there an include file in Loadrunner installation for the zlib.dll ?

      ReplyDelete
    4. solved the typedef issue. It was another compile issue in my code. nothing to do with this typedef.

      ReplyDelete