Showing posts with label xml. Show all posts
Showing posts with label xml. Show all posts

Monday, January 9, 2012

How to Test REST Web Service Using LoadRunner

A simple and easy method of load testing a REST service using LoadRunner is as follows:

  • use the http protocol
  • use web_custom_request
  • specify in web_custom_request the appropriate REST method: 
    • Method=PUT
    • Method=GET
    • Method=DELETE
The following script gives an example of this method in the case of REST PUT request using a JSON request message.  (XML request message would be similar).  One of the fields in the message is parameterized using a random number parameter.  The parameter is given a format of "0000000000000000000000%09lu" to achieve a 32 character-long number string.

Script

Action()
{
    char *request_json_base;
    char *request_json;


    // save web service url to param {URL}
    char *URL = "http://SERVER:8080/Path";
    lr_save_string(URL, "URL_Param");


    // save json request to param {REQUEST_JSON_PARAM}, parameterize "SomeID" as random number
    request_json_base=
     "{" 
     "    \"Field1\"       : \"ValueOfField1\"," 
     "    \"SomeID\"           : \"{SomeID}\","   
     "    \"Field2\"       : \"ValueOfField2\"," 
     "    \"Field3\"       : \"ValueOfField3\"," 
     "}";

    request_json = lr_eval_string(request_json_base);
    lr_save_string(request_json, "REQUEST_JSON_PARAM");
  
    // set http headers
    web_add_header("Content-Type", "application/json; charset=utf-8");


    // validate response
    web_reg_find("Text=success", LAST);


    // send JSON request
    lr_start_transaction("rest_put");


    web_custom_request("post_to_http_jms_provider",
    "URL={URL_Param}",
    "Method=PUT",
    "TargetFrame=",
    "Resource=0",
    "Referer=",
    "Mode=HTTP",
    "Body={REQUEST_JSON_PARAM}",
    LAST); 


    lr_end_transaction("rest_put", LR_AUTO);
}


Console Output

Action.c(49): Notify: Transaction "rest_put" started.
Action.c(51): Notify: Parameter Substitution: parameter "URL_Param" =  "http://SERVER:8080/Path"
Action.c(51): Notify: Parameter Substitution: parameter "REQUEST_JSON_PARAM" =  "{    "Field1"       : "ValueOfField1",    "SomeID"          : "00000000000000000000001244464508",    "Field2"       : "ValueOfField2",    "Field3"       : "ValueOfField3"}"
Action.c(51): t=258ms: 147-byte response headers for "http://SERVER:8080/Path" (RelFrameId=1, Internal ID=1)
Action.c(51):     HTTP/1.1 200 OK\r\n
Action.c(51):     Content-Type: application/octet-stream\r\n
Action.c(51):     Date: Mon, 09 Jan 2012 18:43:07 GMT\r\n
Action.c(51):     Content-Length: 7\r\n
Action.c(51):     \r\n
Action.c(51): t=271ms: 7-byte response body for "http://SERVER:8080/Path" (RelFrameId=1, Internal ID=1)
Action.c(51):     success
Action.c(51): Registered web_reg_find successful for "Text=success" (count=1)   [MsgId: MMSG-26364]
Action.c(51): web_custom_request("post_to_http_jms_provider") was successful, 7 body bytes, 147 header bytes   [MsgId: MMSG-26386]
Action.c(61): Notify: Transaction "rest_put" ended with "Pass" status (Duration: 0.1255 Wasted Time: 0.0000).


Tuesday, January 3, 2012

Handling Client Side Certificates in LoadRunner for Web Services Testing

Web services requiring client side certificates can be handled in LoadRunner as follows:
  • Create a .pem client certificate file.  
    • Client certificates in other formats can be converted to .pem format using a utility such as openssl.
  • Copy the .pem file to the loadrunner script directory
  • Set the .pem file in the loadrunner script using the web_set_certificate_ex method:
    • web_set_certificate_ex( 
    •         "CertFilePath=clientcertificate.pem", 
    •         "CertFormat=PEM", 
    •         "KeyFilePath=clientcertificate.pem", 
    •         "KeyFormat=PEM", 
    •         "Password=testpassword", 
    •         LAST);
  • Post xml to the secure url
The following script provides an example of the client certificate file usage:

#include "as_web.h"
#include "lrw_custom_body.h"

char soapURL[]        = "URL=https://SERVER:8080/Path/v1";

// Verification text
char expectedResponse[] = "<ResponseMessage>Success!</ResponseMessage>";

char requestXMLBody[] = 
"Body="
    "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:urn=\"urn:test:messages:v1\">\n"
"<soap:Header>\n"
"..."
"</soap:Header>\n"
"<soap:Body>\n"
"..."
"</soap:Body>\n"
    "</soap:Envelope>\n";
                  

Action()
{
PostXML( requestXMLBody, soapUR );
return 0;
}


void PostXML( char* xmlBody, char* soapURL, char* transactionName )
{
   /******** CreateAuthAccount Transaction ********/
   
   web_add_header( "Content-Type", "application/soap+xml" );

   web_set_certificate_ex( 
        "CertFilePath=clientcertificate.pem", 
        "CertFormat=PEM", 
        "KeyFilePath=clientcertificate.pem", 
        "KeyFormat=PEM", 
        "Password=testpassword", 
        LAST); 

   // save the response
   web_reg_save_param( "transactionResponse",
                       "LB=",
                       "RB=",
                       "Search=Body",
                       "NOTFOUND=Warning",
                        LAST );
   
   lr_start_transaction("post");

   web_custom_request( "postXML",
                       soapURL,
                       "Method=POST",
                       xmlBody,
                       LAST );

   // check for errors in response
   if( 0 != strstr( lr_eval_string( "{transactionResponse}" ), "ServiceException" ) )
   {
          lr_end_transaction( "post", LR_FAIL );
 lr_error_message( "ERROR (exception found in response): %s", lr_eval_string( "{transactionResponse}" ) );
   }
   else
   {
  lr_end_transaction("post", LR_PASS);
  lr_log_message( lr_eval_string( "{transactionResponse}" ));
   }
}

Thursday, December 29, 2011

Simple LoadRunner Method to Post XML to Web Service

Here is a very simple method for posting XML to a web service from loadrunner using http protocol. This method is somewhat simpler than using the web service protocol.

XML Request In-Line
In this scenario:
  • url is saved to a parameter
  • xml request is saved to a parameter
  • http headers are defined
  • response validation is defined
  • request is sent

Here is the script:

Action()
{
    char *request_xml;


    // save web service url to param
    char *URL = "http://www.webservicex.com/globalweather.asmx";
    lr_save_string(URL, "URL_Param");


// save xml request to param
request_xml=
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
 "<soap:Body>"
  "<GetWeather xmlns=\"http://www.webserviceX.NET\">"
"<CityName>Seattle</CityName>"
"<CountryName>United States</CountryName>"
  "</GetWeather>"
 "</soap:Body>"
"</soap:Envelope>";


lr_save_string(request_xml, "REQUEST_XML_PARAM");
  
// add http headers
web_add_header("Content-Type", "text/xml; charset=utf-8");
        web_add_header("Host", "www.webservicex.com");
web_add_header("SOAPAction", "http://www.webserviceX.NET/GetWeather");


        // validate response
web_reg_find("Text=SEATTLE-TACOMA INTERNATIONAL  AIRPORT , WA, United States", LAST);


// send request
lr_start_transaction("post_xml");


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


lr_end_transaction("post_xml", LR_AUTO);
}


Sample Output
Here is the sample output:

Virtual User Script started
Starting action vuser_init.
Web Turbo Replay of LoadRunner 9.10.0 for WIN2003; WebReplay85 build 5896   [MsgId: MMSG-27143]
Run Mode: HTML   [MsgId: MMSG-26000]
Run-Time Settings file: "E:\bin\PerformanceCenter\scripts\POST_XML_TEST\\default.cfg"   [MsgId: MMSG-27141]
Ending action vuser_init.
Running Vuser...
Starting iteration 1.
Starting action Action.
Action.c(7): Notify: Saving Parameter "URL_Param = http://www.webservicex.com/globalweather.asmx"
Action.c(21): Notify: Saving Parameter "REQUEST_XML_PARAM = <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetWeather xmlns="http://www.webserviceX.NET"><CityName>Seattle</CityName><CountryName>United States</CountryName></GetWeather></soap:Body></soap:Envelope>"
Action.c(24): Warning -26593: The header being added may cause unpredictable results when applied to all ensuing URLs. It is added anyway   [MsgId: MWAR-26593]
Action.c(24): web_add_header("Content-Type") highest severity level was "warning"   [MsgId: MMSG-26391]
Action.c(25): Warning -26593: The header being added may cause unpredictable results when applied to all ensuing URLs. It is added anyway   [MsgId: MWAR-26593]
Action.c(25): web_add_header("Host") highest severity level was "warning"   [MsgId: MMSG-26391]
Action.c(26): web_add_header("SOAPAction") was successful   [MsgId: MMSG-26392]
Action.c(29): Registering web_reg_find was successful   [MsgId: MMSG-26390]
Action.c(32): Notify: Transaction "post_xml" started.
Action.c(34): Notify: Parameter Substitution: parameter "URL_Param" =  "http://www.webservicex.com/globalweather.asmx"
Action.c(34): Notify: Parameter Substitution: parameter "REQUEST_XML_PARAM" =  "<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetWeather xmlns="http://www.webserviceX.NET"><CityName>Seattle</CityName><CountryName>United States</CountryName></GetWeather></soap:Body></soap:Envelope>"
Action.c(34): t=244ms: 277-byte response headers for "http://www.webservicex.com/globalweather.asmx" (RelFrameId=1, Internal ID=1)
Action.c(34):     HTTP/1.1 200 OK\r\n
Action.c(34):     Cache-Control: private, max-age=0\r\n
Action.c(34):     Content-Type: text/xml; charset=utf-8\r\n
Action.c(34):     Content-Encoding: gzip\r\n
Action.c(34):     Vary: Accept-Encoding\r\n
Action.c(34):     Server: Microsoft-IIS/7.0\r\n
Action.c(34):     X-AspNet-Version: 4.0.30319\r\n
Action.c(34):     X-Powered-By: ASP.NET\r\n
Action.c(34):     Date: Thu, 29 Dec 2011 22:34:56 GMT\r\n
Action.c(34):     Content-Length: 728\r\n
Action.c(34):     \r\n
Action.c(34): t=264ms: 728-byte ENCODED response body received for "http://www.webservicex.com/globalweather.asmx" (RelFrameId=1, Internal ID=1)
Action.c(34): t=265ms: 1103-byte DECODED response body for "http://www.webservicex.com/globalweather.asmx" (RelFrameId=1, Internal ID=1)
Action.c(34):     <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.or
Action.c(34):     g/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://
Action.c(34):     www.w3.org/2001/XMLSchema"><soap:Body><GetWeatherResponse xmlns="http://www.webserviceX.NE
Action.c(34):     T"><GetWeatherResult>&lt;?xml version="1.0" encoding="utf-16"?&gt;\r\n
Action.c(34):     &lt;CurrentWeather&gt;\r\n
Action.c(34):       &lt;Location&gt;SEATTLE-TACOMA INTERNATIONAL  AIRPORT , WA, United States (KSEA) 47-27N 
Action.c(34):     122-19W 136M&lt;/Location&gt;\r\n
Action.c(34):       &lt;Time&gt;Dec 29, 2011 - 04:53 PM EST / 2011.12.29 2153 UTC&lt;/Time&gt;\r\n
Action.c(34):       &lt;Wind&gt; from the SE (140 degrees) at 9 MPH (8 KT):0&lt;/Wind&gt;\r\n
Action.c(34):       &lt;Visibility&gt; 10 mile(s):0&lt;/Visibility&gt;\r\n
Action.c(34):       &lt;SkyConditions&gt; overcast&lt;/SkyConditions&gt;\r\n
Action.c(34):       &lt;Temperature&gt; 46.0 F (7.8 C)&lt;/Temperature&gt;\r\n
Action.c(34):       &lt;DewPoint&gt; 39.9 F (4.4 C)&lt;/DewPoint&gt;\r\n
Action.c(34):       &lt;RelativeHumidity&gt; 79%&lt;/RelativeHumidity&gt;\r\n
Action.c(34):       &lt;Pressure&gt; 29.93 in. Hg (1013 hPa)&lt;/Pressure&gt;\r\n
Action.c(34):       &lt;Status&gt;Success&lt;/Status&gt;\r\n
Action.c(34):     &lt;/CurrentWeather&gt;</GetWeatherResult></GetWeatherResponse></soap:Body></soap:Envelope
Action.c(34):     >
Action.c(34): Registered web_reg_find successful for "Text=SEATTLE-TACOMA INTERNATIONAL  AIRPORT , WA, United States" (count=1)   [MsgId: MMSG-26364]
Action.c(34): web_custom_request("post_to_http_jms_provider") was successful, 728 body bytes, 277 header bytes   [MsgId: MMSG-26386]
Action.c(44): Notify: Transaction "post_xml" ended with "Pass" status (Duration: 0.1738 Wasted Time: 0.0000).
Ending action Action.
Ending iteration 1.
Ending Vuser...
Starting action vuser_end.
Ending action vuser_end.
Vuser Terminated.



XML Request From Parameter File
The xml request message can also be saved in a parameter file rather than being defined in-line.  In this scenario:
  • url is saved to a parameter
  • xml request is saved in a parameter file which is set to update row on "sequential", update value on "once".
  • http headers are defined
  • response validation is defined
  • request is sent

Here is the script:

Action()
{
    // save web service url to parameter
    char *URL = "http://www.webservicex.com/globalweather.asmx";
    lr_save_string(URL, "URL_Param");
  
    // add http headers
    web_add_header("Content-Type", "text/xml; charset=utf-8");
    web_add_header("Host", "www.webservicex.com");
    web_add_header("SOAPAction", "http://www.webserviceX.NET/GetWeather");


    // validate response
    web_reg_find("Text=SEATTLE-TACOMA INTERNATIONAL  AIRPORT , WA, United States", LAST);


    // send request
    lr_start_transaction("post_xml");


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


    lr_end_transaction("post_xml", LR_AUTO);
}



Parameter File
Here is the parameter file Requst.dat, with the xml defined on a single line, parameter properties of update row on "sequential", update value on "once":

Request
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetWeather xmlns="http://www.webserviceX.NET"><CityName>Seattle</CityName><CountryName>United States</CountryName></GetWeather></soap:Body></soap:Envelope>



Sample Output
Here is the sample output:

Virtual User Script started
Starting action vuser_init.
Web Turbo Replay of LoadRunner 9.10.0 for WIN2003; WebReplay85 build 5896   [MsgId: MMSG-27143]
Run Mode: HTML   [MsgId: MMSG-26000]
Run-Time Settings file: "E:\bin\PerformanceCenter\scripts\POST_XML_FROM_FILE_TEST\\default.cfg"   [MsgId: MMSG-27141]
Ending action vuser_init.
Running Vuser...
Starting iteration 1.
Starting action Action.
Action.c(6): Notify: Saving Parameter "URL_Param = http://www.webservicex.com/globalweather.asmx"
Action.c(9): Warning -26593: The header being added may cause unpredictable results when applied to all ensuing URLs. It is added anyway   [MsgId: MWAR-26593]
Action.c(9): web_add_header("Content-Type") highest severity level was "warning"   [MsgId: MMSG-26391]
Action.c(10): Warning -26593: The header being added may cause unpredictable results when applied to all ensuing URLs. It is added anyway   [MsgId: MWAR-26593]
Action.c(10): web_add_header("Host") highest severity level was "warning"   [MsgId: MMSG-26391]
Action.c(11): web_add_header("SOAPAction") was successful   [MsgId: MMSG-26392]
Action.c(14): Registering web_reg_find was successful   [MsgId: MMSG-26390]
Action.c(17): Notify: Transaction "post_xml" started.
Action.c(19): Notify: Parameter Substitution: parameter "URL_Param" =  "http://www.webservicex.com/globalweather.asmx"
Action.c(19): Notify: Parameter Substitution: parameter "Request_From_File" =  "<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetWeather xmlns="http://www.webserviceX.NET"><CityName>Seattle</CityName><CountryName>United States</CountryName></GetWeather></soap:Body></soap:Envelope>"
Action.c(19): t=210ms: 277-byte response headers for "http://www.webservicex.com/globalweather.asmx" (RelFrameId=1, Internal ID=1)
Action.c(19):     HTTP/1.1 200 OK\r\n
Action.c(19):     Cache-Control: private, max-age=0\r\n
Action.c(19):     Content-Type: text/xml; charset=utf-8\r\n
Action.c(19):     Content-Encoding: gzip\r\n
Action.c(19):     Vary: Accept-Encoding\r\n
Action.c(19):     Server: Microsoft-IIS/7.0\r\n
Action.c(19):     X-AspNet-Version: 4.0.30319\r\n
Action.c(19):     X-Powered-By: ASP.NET\r\n
Action.c(19):     Date: Thu, 29 Dec 2011 22:33:25 GMT\r\n
Action.c(19):     Content-Length: 728\r\n
Action.c(19):     \r\n
Action.c(19): t=246ms: 728-byte ENCODED response body received for "http://www.webservicex.com/globalweather.asmx" (RelFrameId=1, Internal ID=1)
Action.c(19): t=247ms: 1103-byte DECODED response body for "http://www.webservicex.com/globalweather.asmx" (RelFrameId=1, Internal ID=1)
Action.c(19):     <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.or
Action.c(19):     g/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://
Action.c(19):     www.w3.org/2001/XMLSchema"><soap:Body><GetWeatherResponse xmlns="http://www.webserviceX.NE
Action.c(19):     T"><GetWeatherResult>&lt;?xml version="1.0" encoding="utf-16"?&gt;\r\n
Action.c(19):     &lt;CurrentWeather&gt;\r\n
Action.c(19):       &lt;Location&gt;SEATTLE-TACOMA INTERNATIONAL  AIRPORT , WA, United States (KSEA) 47-27N 
Action.c(19):     122-19W 136M&lt;/Location&gt;\r\n
Action.c(19):       &lt;Time&gt;Dec 29, 2011 - 04:53 PM EST / 2011.12.29 2153 UTC&lt;/Time&gt;\r\n
Action.c(19):       &lt;Wind&gt; from the SE (140 degrees) at 9 MPH (8 KT):0&lt;/Wind&gt;\r\n
Action.c(19):       &lt;Visibility&gt; 10 mile(s):0&lt;/Visibility&gt;\r\n
Action.c(19):       &lt;SkyConditions&gt; overcast&lt;/SkyConditions&gt;\r\n
Action.c(19):       &lt;Temperature&gt; 46.0 F (7.8 C)&lt;/Temperature&gt;\r\n
Action.c(19):       &lt;DewPoint&gt; 39.9 F (4.4 C)&lt;/DewPoint&gt;\r\n
Action.c(19):       &lt;RelativeHumidity&gt; 79%&lt;/RelativeHumidity&gt;\r\n
Action.c(19):       &lt;Pressure&gt; 29.93 in. Hg (1013 hPa)&lt;/Pressure&gt;\r\n
Action.c(19):       &lt;Status&gt;Success&lt;/Status&gt;\r\n
Action.c(19):     &lt;/CurrentWeather&gt;</GetWeatherResult></GetWeatherResponse></soap:Body></soap:Envelope
Action.c(19):     >
Action.c(19): Registered web_reg_find successful for "Text=SEATTLE-TACOMA INTERNATIONAL  AIRPORT , WA, United States" (count=1)   [MsgId: MMSG-26364]
Action.c(19): web_custom_request("post_xml") was successful, 728 body bytes, 277 header bytes   [MsgId: MMSG-26386]
Action.c(29): Notify: Transaction "post_xml" ended with "Pass" status (Duration: 0.1629 Wasted Time: 0.0000).
Ending action Action.
Ending iteration 1.
Ending Vuser...
Starting action vuser_end.
Ending action vuser_end.
Vuser Terminated.

Varying Parameters in the Request

It is also quite easy to vary the input parameters passed in the request message using the function lr_xml_set_values as follows.  In this case: 
  • the field "CityName" in the request xml is specified
  • a new value for CityName is specified
  • the resulting request xml is put in a parameter
  • the updated request is sent
 // vary parameters
lr_xml_set_values("XML=\{Request_From_File\}",
"Query=//CityName",
"Value=Spokane",
"ResultParam=XML_With_Substitution",
LAST);

// add http headers
web_add_header("Content-Type", "text/xml; charset=utf-8");
        web_add_header("Host", "www.webservicex.com");
web_add_header("SOAPAction", "http://www.webserviceX.NET/GetWeather");

// validate response
web_reg_find("Text=FELTS FIELD, WA, United States", LAST);

// send request
lr_start_transaction("post_xml");

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

lr_end_transaction("post_xml", LR_AUTO);

The request variables can also be pulled from a parameter file as follows:
        // vary parameters
lr_xml_set_values("XML=\{Request_From_File\}",
"Query=//CityName",
"Value=\{CityNameParameter\}",
"ResultParam=XML_With_Substitution",
LAST);

Sample Output


Action.c(32): Notify: Parameter Substitution: parameter "Request_From_File" =  "<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetWeather xmlns="http://www.webserviceX.NET"><CityName>Seattle</CityName><CountryName>United States</CountryName></GetWeather></soap:Body></soap:Envelope>"
Action.c(32): Notify: Saving Parameter "XML_With_Substitution = <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body><GetWeather xmlns="http://www.webserviceX.NET"><CityName>Spokane</CityName><CountryName>United States</CountryName></GetWeather></soap:Body></soap:Envelope>"
Action.c(32): "lr_xml_set_values" succeeded, 1 match processed
Action.c(39): Warning -26593: The header being added may cause unpredictable results when applied to all ensuing URLs. It is added anyway   [MsgId: MWAR-26593]
Action.c(39): web_add_header("Content-Type") highest severity level was "warning"   [MsgId: MMSG-26391]
Action.c(40): Warning -26593: The header being added may cause unpredictable results when applied to all ensuing URLs. It is added anyway   [MsgId: MWAR-26593]
Action.c(40): web_add_header("Host") highest severity level was "warning"   [MsgId: MMSG-26391]
Action.c(41): web_add_header("SOAPAction") was successful   [MsgId: MMSG-26392]
Action.c(44): Notify: Transaction "post_xml" started.
Action.c(46): Notify: Parameter Substitution: parameter "URL_Param" =  "http://www.webservicex.com/globalweather.asmx"
Action.c(46): Notify: Parameter Substitution: parameter "XML_With_Substitution" =  "<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body><GetWeather xmlns="http://www.webserviceX.NET"><CityName>Spokane</CityName><CountryName>United States</CountryName></GetWeather></soap:Body></soap:Envelope>"
Action.c(46): t=556ms: 277-byte response headers for "http://www.webservicex.com/globalweather.asmx" (RelFrameId=1, Internal ID=2)
Action.c(46):     HTTP/1.1 200 OK\r\n
Action.c(46):     Cache-Control: private, max-age=0\r\n
Action.c(46):     Content-Type: text/xml; charset=utf-8\r\n
Action.c(46):     Content-Encoding: gzip\r\n
Action.c(46):     Vary: Accept-Encoding\r\n
Action.c(46):     Server: Microsoft-IIS/7.0\r\n
Action.c(46):     X-AspNet-Version: 4.0.30319\r\n
Action.c(46):     X-Powered-By: ASP.NET\r\n
Action.c(46):     Date: Thu, 29 Dec 2011 22:53:27 GMT\r\n
Action.c(46):     Content-Length: 706\r\n
Action.c(46):     \r\n
Action.c(46): t=578ms: 706-byte ENCODED response body received for "http://www.webservicex.com/globalweather.asmx" (RelFrameId=1, Internal ID=2)
Action.c(46): t=579ms: 1081-byte DECODED response body for "http://www.webservicex.com/globalweather.asmx" (RelFrameId=1, Internal ID=2)
Action.c(46):     <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.or
Action.c(46):     g/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://
Action.c(46):     www.w3.org/2001/XMLSchema"><soap:Body><GetWeatherResponse xmlns="http://www.webserviceX.NE
Action.c(46):     T"><GetWeatherResult>&lt;?xml version="1.0" encoding="utf-16"?&gt;\r\n
Action.c(46):     &lt;CurrentWeather&gt;\r\n
Action.c(46):       &lt;Location&gt;FELTS FIELD, WA, United States (KSFF) 47-41N 117-19W 609M&lt;/Location&g
Action.c(46):     t;\r\n
Action.c(46):       &lt;Time&gt;Dec 29, 2011 - 04:53 PM EST / 2011.12.29 2153 UTC&lt;/Time&gt;\r\n
Action.c(46):       &lt;Wind&gt; from the SSW (210 degrees) at 9 MPH (8 KT):0&lt;/Wind&gt;\r\n
Action.c(46):       &lt;Visibility&gt; 10 mile(s):0&lt;/Visibility&gt;\r\n
Action.c(46):       &lt;SkyConditions&gt; mostly clear&lt;/SkyConditions&gt;\r\n
Action.c(46):       &lt;Temperature&gt; 43.0 F (6.1 C)&lt;/Temperature&gt;\r\n
Action.c(46):       &lt;DewPoint&gt; 33.1 F (0.6 C)&lt;/DewPoint&gt;\r\n
Action.c(46):       &lt;RelativeHumidity&gt; 67%&lt;/RelativeHumidity&gt;\r\n
Action.c(46):       &lt;Pressure&gt; 29.99 in. Hg (1015 hPa)&lt;/Pressure&gt;\r\n
Action.c(46):       &lt;Status&gt;Success&lt;/Status&gt;\r\n
Action.c(46):     &lt;/CurrentWeather&gt;</GetWeatherResult></GetWeatherResponse></soap:Body></soap:Envelope
Action.c(46):     >
Action.c(46): web_custom_request("post_xml") was successful, 706 body bytes, 277 header bytes   [MsgId: MMSG-26386]
Action.c(56): Notify: Transaction "post_xml" ended with "Pass" status (Duration: 0.2966).
Ending action Action.
Ending iteration 1.
Ending Vuser...
Starting action vuser_end.
Ending action vuser_end.
Vuser Terminated.



Saving Parameters From XML Response
The XML response can be saved in a parameter "Response" as follows:

    // save response
    web_reg_save_param("Response", "LB=", "RB=", "Search=Body", LAST);


With the response, fields from the xml can be extracted as follows to later be used in the next xml request.  In this case field "FieldInResponseXml" is saved to parameter "ResponseFieldParam":
   lr_xml_get_values("XML=\{Response\}",
     "ValueParam=ResponseFieldParam",
     "Query=//FieldInResponseXml",
     LAST);

The parameter {ResponseFieldParam} can then be used to construct the next xml request.




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.