Skip to main content

skip to main content

developerWorks  >  Rational  >

Reading HTTP VU scripts

developerWorks
Document options

Document options requiring JavaScript are not displayed


Rate this page

Help us improve this content


Level: Introductory

Michael Kelly, Software Engineer, QA, Liberty Mutual

08 Jul 2004

Understanding the code in an HTTP VU script will help you design better performance tests. This article walks you through a typical script.

This article takes a beginner's look at the composition of and commands in an HTTP virtual user (VU) script recorded with the IBM® Rational® Robot™ software. It's intended for those new to performance testing with Robot, as well as for testers who've been using recorded scripts for a while and now would like to know what those scripts contain. Understanding the code and what's happening in the script will help you better design your performance tests in the future.

This article walks you through recording an HTTP VU script and then looks in detail at each of the commands in that script, offering hints and strategies where appropriate. You can download a copy of the script recorded in the article and then copy and paste it into a blank VU script in Robot. However, if you have the resources available while you read this, I encourage you to follow along and record your own script.

Recording the script

For our example, you'll record a script while you open the IBM developerWorks site and rate an article about performance testing. I used version 2002 of Robot to record my script.

  1. First you'll clear the cookies from your browser (always a good practice when recording sessions). In Internet Explorer, click Tools > Internet Options and then click the Delete Cookies button in the window that appears. Give it a few seconds to complete, click OK, and close the browser.
  2. In Robot, click File > Record Session, as shown below. This opens the Record Session window.

the Record Session window

  1. Click the Options button. This opens the Session Record Options window.
  2. Click the Method tab and verify that the "API Recorder" radio button is selected, which is the default setting. This will enable Robot to record socket API calls between the client and the server, with recording occurring on the client rather than on the network wire.

Click the Method tab and verify that the API Recorder radio button is selected

  1. Click the Generator tab and verify that the "Use datapools" checkbox is selected and the Return Data settings look like those illustrated below. The purpose of these settings will be discussed later in the article.

Click the Generator tab and verify that the Use datapools checkbox is selected

  1. Click the Generator Filtering tab. The options on this tab set the filtering for the session. You'll want to use Auto Filtering (to let Robot do the work for you) and to make sure HTTP is selected as a protocol. Don't worry if other protocols are selected as well.

Click the Generator Filtering tab

  1. Finally, click the Generator per Protocol tab. Ensure that HTTP is selected and that the three checkboxes below it are selected (these are the default settings out of the box). These settings will be discussed later in the article as well.

click the Generator per Protocol tab

  1. Click OK. Once you're returned to the Record Session window, enter a name for the session and click OK.

enter a name for the session and click OK

  1. This will open the Session Recorder and the Start Application dialog. Enter the executable for your browser in the "Executable" field (the default installation path for IE is C:\Program Files\Internet Explorer\IEXPLORE.exe) and enter the URL for IBM developerWorks (www-136.ibm.com/developerworks/) in the "Program arguments" field. Click OK.

the Session Recorder and the Start Application dialog

  1. After a short delay, the browser will open to the developerWorks page. Enter "Performance Testing" in the "Search for" field and click the Search button.

Enter Performance Testing in the Search for field and click the Search button

  1. On the search results screen, choose an article on performance testing. In my script I selected "High-volume performance testing on Windows using Rational TestManager," but you can choose any article that's available.

choose an article on performance testing

  1. When the article opens, scroll to the bottom and fill out the feedback section for the article. Be kind to the author (especially if the article is one of mine). Click the Submit feedback button when finished.

fill out the feedback section for the article and Click the Submit feedback button when finished

  1. When the thank-you page appears, click the link that takes you back to the developerWorks home page.

click the link that takes you back to the developerWorks home page

  1. Close the browser. When Robot prompts you to stop recording, click Yes.
  2. When the Stop Recording window appears, enter the name of the script and click OK. Robot will generate the script and open it for you.

Robot will generate the script and open it for you



Back to top


Looking at the script

Now we'll look at the code generated during the session. We'll start at the top of the script and work our way down. When we encounter a new command, I'll explain it in detail.

Environment variables

The above command includes the VU library header

The above command -- inserted automatically for scripts generated from recording HTTP, SQL, and socket sessions (which is what we did) -- includes the VU library header. A header file contains a collection of definitions and macros.

The above section of code sets the environment variables for the script

The above section of code sets the environment variables for the script. The push command "pushes" the value of each environment variable to the top of the stack. This means that the variable is set to that value until another value is put on the stack or the value is "popped" from the stack.

Http_control controls which status values are accepted when a VU script is played back. The values are set to HTTP_PARTIAL_OK | HTTP_CACHE_OK | HTTP_REDIRECT_OK because those are the settings we selected on the Generator per Protocol tab in the Session Record Options window, in step 7 above. These settings mean that our script will allow partial responses, cache responses, and redirects. The meanings of these responses and the codes associated with them will be discussed below.

Timeout_scale controls the percentage multiplier applied to the timeout delay (Timeout_val, discussed below), which specifies how long an emulation command should wait for a response from the server. If a response is received within the time allowed, the appropriate logging and recording is done, and the emulation continues with execution of the next statement. On the other hand, if an emulation command has been waiting for longer than the value of Timeout_val times the multiplier you set with Timeout_scale, the emulation command times out. Setting Timeout_scale to a value of 100% represents no change from the timeout value. A value of 50% means half the delay, and 200% means twice the delay. This value is set to 200% by default and can be changed either in the script code or at the suite level.

Here's how you change Timeout_scale within a suite (whatever value you set in the suite will override the value you set in the script):

  1. Click Suite > Edit Settings.

Click Suite > Edit Settings

  1. Click the TSS Environment Variables button for the user group you want to change.

Click the TSS Environment Variables button for the user group you want to change

  1. In the TSS Environment Variables window, click the VU Response Timeout tab and set the "Scale timeout by" value to the percentage you want.

click the VU Response Timeout tab and set the Scale timeout by value to the percentage you want

Getting back to our script, Think_def specifies the starting point of the think time interval for the current send emulation command (discussed below). A think time interval is simply the time that a typical user would delay, or think, between submitting commands. By default the value is set to "LR" (last received), which means that the think time interval begins at the time the last data of the previous receive emulation command (also discussed below) is received. If there's no intervening receive emulation command, the think time interval begins when the previous send emulation command is completed.

You can set this value, like the Timeout_scale variable, at the suite level (this value will override the value set in the script). Follow these steps:

  1. Click Suite > Edit Settings and then in the Settings window click the TSS Environment Variables button for the user group you want to change.
  2. In the TSS Environment Variables window, click the Think Time tab and set the "Starting point of think time" value to one of the following options:
    • First connection sets the starting point to when the most recent attempt to connect to the server for the previous emulation command was started.
    • First received sets the starting point to when the first part of the response to the previous emulation command comes back from the server.
    • First sent sets the starting point to when the beginning of the previous emulation command was sent to the server.
    • Last connection sets the starting point to when the most recent connection of the previous emulation command to the server was completed.
    • Last received sets the starting point to when the last data for the previous emulation command is received. This is the default.
    • Last sent sets the starting point to when the last part of the response to the previous emulation command comes back from the server.

click the Think Time tab and set the Starting point of think time value

Back to our script again. Min_tmout is simply a variable used to store the value of the minimum timeout. This value can be any integer from 0 to15000000 and represents time in milliseconds.

Timeout_val specifies how long an emulation command waits for a server response before it times out. If this value is too small, commands requesting large amounts of data or complex operations will time out even though the server may respond correctly.

This value can also be set at the suite level in the TSS Environment Variables window (overriding the value set in the script). Follow these steps:

  1. Click Suite > Edit Settings and then in the Settings window click the TSS Environment Variables button for the user group you want to change.
  2. In the TSS Environment Variables window, click the VU Response Timeout tab and set the "Timeout" value to the number of milliseconds desired.

click the VU Response Timeout tab and set the Timeout value to the number of milliseconds desired

Moving down in our script, the above line of code initializes the Think_avg environment variable for the script. This variable in an integer between 0 and 2000000000 used to specify the duration, in milliseconds, of the average think time interval. You'll see this value repeatedly in the script, as it gets set for every emulation command.

This value can also be set at the suite level in the TSS Environment Variables window (overriding the value set in the script). You know the drill by now. The "Average think time" setting is located on the Think Time tab, the same tab as the setting for the Think_def variable.

Datapools

opening the datapool created for the script

The above lines open the datapool created for the script (datapool_open) and set the cursor to the first row (datapool_fetch). The DP1 variable is used as a pointer reference to the datapool. As you may recall, we indicated that we wanted to use datapools during step 5 of recording the script.

A datapool is a convenient way to supply variable data values to a script. When you use a datapool, each virtual tester that runs the script can send realistic values to the server, and a single virtual tester that performs the same transaction multiple times can send realistic or unique values to the server in each transaction. If you don't use a datapool, each virtual tester sends the same values to the server (the hard-coded values you provided when you recorded the script).

The structure for the datapool is the last thing created in the script. If you scroll down to the bottom of the script, you'll see something similar to the following:

datapool script

The DATAPOOL_CONFIG statement controls datapool creation and access. I won't go into the details of what all the flags and arguments for the command represent (the online VU Language Reference does a great job), but I'll mention that you can edit these values by performing the following steps:

  1. In Robot, click Edit > Datapool Information.

click Edit > Datapool Information

  1. Make the desired changes in the Configure Datapool in Script window. You can edit column usage, specify playback behaviors, create the datapool, and edit data.

Make the desired changes in the Configure Datapool in Script window

When you exit the Configure Datapool in Script window, your script will be updated and saved with the changes you made.

Send emulation commands

Going back up toward the top of the script, just below the datapool calls we find the following:

emulation command

In an HTTP VU script, the only send emulation command is http_request. This command emulates all HTTP protocol request primitives: GET, HEAD, POST, PUT, TRACE, LINK, UNLINK, DELETE, OPTIONS, and COPY. The http_request command is affected by the VU environment variables Timeout_val and Timeout_scale, discussed above.

In the script we recorded, this command is executed approximately 70 times. It's important that you understand the makeup of this command. The command syntax is as follows:

int http_request [cmd-id] primary-addr [, secondary-addr] [, flags], text

We'll take this syntax one piece at a time. The int or integer return variable contains the connection ID that's used as a reference for subsequent interactions with the Web server. In the excerpt from our script above, it's www_136_ibm_com. This variable is automatically generated based on the Web site the request is sent to, and a number is appended to it and increased by 1 for each http_request after the first one. For example:

www_136_ibm_com
www_136_ibm_com_1
www_136_ibm_com_2

If this variable is missing, the send emulation command uses the same connection ID the last command used. If this command was generated automatically, in the comment above the command you'll see the name of the connection being used.

The following code snippet, a couple of lines farther down in the script, has a cmd-id or command ID of ["Sample ~007"]. In the previous example, the command ID was ["Sample ~001"].

The following code snippet, a couple of lines farther down in the script, has a cmd-id or command ID of [Sample ~007].

These command IDs are used to identify the command in both the script and the various log files (as shown in Figures 1, 2, and 3). Just as the return variable for http_request was incremented after the first one, so is the command ID.

Sample log entries in Performance Report Output, using command IDs
Figure 1: Sample log entries in Performance Report Output, using command IDs


Sample log entries in Command Status Report Output, using command IDs
Figure 2: Sample log entries in Command Status Report Output, using command IDs


Sample test log entries, using command IDs
Figure 3: Sample test log entries, using command IDs
(click here to enlarge)

The generated IDs have the virtue of being unique, but I often find it helpful to replace them with values that are more meaningful. This makes both the code and the log files easier to read and debug. For example, I might replace ["Sample ~001"] with ["C_GIF Verification ~001"]. Notice that I left the ~001 at the end of the ID. This makes searching the script to find the command a little easier -- you only have to type 001 in the find dialog and not C_GIF Verification.

The next two arguments to http_request are the primary and secondary addresses for the request. These values are string expressions containing the host computer name and the port number for the Web server. In the example, www-136.ibm.com is the name of the Web server, and 80 is the number of the port to which we're connecting. The secondary address isn't passed, because the connection is an HTTP_CONN_DIRECT connection.

The next argument contains the flags for the type of connection desired. These connection flags are defined in the VU.h file, as follows:

  • HTTP_CONN_DIRECT -- used for a direct connection to the server
  • HTTP_CONN_PROXY -- used when connecting through a proxy server
  • HTTP_CONN_GATEWAY -- currently unused
  • HTTP_CONN_TUNNEL -- currently unused
  • HTTP_CONN_SECURE -- used for a secure connection

The final argument is the text of the request, a string containing the request and the request headers. These headers are used to send information about the HTTP message and have the following format:

name: value\r\n

Here's an example from our script of what that string might look like:

"GET /developerworks/i/c.gif HTTP/1.1\r\n"
"Accept: */*\r\n"
"Referer: http://www-136.ibm.com/developerworks/\r\n"
"Accept-Language: en-us\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR"
" 1.1.4322)\r\n"
"Host: www-136.ibm.com\r\n"
"Connection: Keep-Alive\r\n"
"Cookie: IBMSurveyTest=isEnabled\r\n"
"\r\n";

If you need help finding information on a specific header, MSDN is a good starting point.

Server connections

Continuing down through the script, we see these lines:

server connection

Server_connection is an environment variable that identifies the current server connection over which emulation commands operate. In our example, when we issued the http_request command we stored the connection ID for the server in the variable www_136_ibm_com. In the above code snippet, we're setting the current server connection to that ID. A couple of lines down (I deleted the code between the commands in the snippet) we issue an http_disconnect to close that connection to the Web server.

It's important to note that multiple connections can be open at one time. However, you can only manipulate the last server referenced in the set Server_connection command. If you skim through the script, you'll see several places where the server is switched, validations are made, the server is set back, validations are made again, the server is switched again, and so on. Make sure you're using meaningful server variable names when possible and keep track of the http_disconnect for each server.

Receive emulation commands

receive emulation commands

For an HTTP VU script, there are three receive emulation commands: http_header_recv, http_nrecv, and http_recv.

The http_header_recv command receives header metadata sent from a Web server when a client requests a page. Such metadata might include protocol; type; URL address; size of page; date created, date last modified, and date last updated; as well as an indication of the security status of your connection. The metadata received is stored in the read-only variable _response and is overwritten when you issue another receive emulation command. If Timeout_val (subject to scaling) milliseconds elapse before the http_header_recv is satisfied, the command fails. In the script line above, this receive emulation command is expecting the Web server to return a status code of 302 or "Moved Temporarily." Typically you'd be expecting a status code of 200 or "OK."

When we looked at the Http_control command above, I said that command controls which status values are accepted when a VU script is played back. This is where that value gets checked. Table 1 shows which values are accepted from the Web server.

A value of . . . Indicates the playback script will accept . . .
0exact matches only
HTTP_PARTIAL_OK206 for 200 and 200 for 206
HTTP_PERM_REDIRECT_OK301 for 200 and 200 for 301
HTTP_TEMP_REDIRECT_OK302 for 200 and 200 for 302
HTTP_REDIRECT_OK301 or 302 for 200 and 200 for 301 or 302
HTTP_CACHE_OK304 for 200 and 200 for 304
Table 1: Status values and their meanings

You can set Http_control to accept multiple values -- for example:

Http_control = HTTP_REDIRECT_OK | HTTP_CACHE_OK;

If there's a mismatch between the expected HTTP return code and the actual code, and the Http_control variable isn't set to accept the discrepancy, then the mismatch is flagged as an error in the test log. If the Http_control variable has been set to accept the discrepancy, no note is made in the log.

The http_nrecv command receives a user-specified number of bytes from a Web server. This emulation command succeeds when it receives either a specific number of bytes or a percentage of the total bytes from the server, as specified by the user. The data received is stored in the read-only variable _response and is overwritten when you issue another receive emulation command. If Timeout_val (subject to scaling) milliseconds elapse before the http_nrecv is satisfied, the command fails. In the script line above, http_nrecv is returning 100% of the bytes available.

The http_recv command receives data from a Web server until a specified text string occurs. The data received is stored in the read-only variable _response and is overwritten when you issue another receive emulation command. Http_recv also waits for Timeout_val milliseconds before failing. The example script doesn't contain a call like this, but it might look like the following:

http_recv ["Sample ~077"] "Page</title>\r\n";

Here's a tip: When errors are encountered, if you click the Virtual Tester Associated Data tab in the log you can see the value of _response, as illustrated in Figure 4. This can be useful in determining the cause of the failure.

The value of _response, shown on the Virtual Tester Associated Data tab
Figure 4: The value of _response, shown on the Virtual Tester Associated Data tab

Values returned from the server

Moving down through the script, we next encounter this block of code:

values returned from the server

The http_find_values command is used to extract and correlate data from the server. This data is stored in an array, where you can access it at runtime. When you play back a script, the script uses either the exact values that you recorded, values returned from a datapool you created (discussed briefly above), or values contained in the array returned from the server in response to the http_find_values command.

The pattern of the block shown above is common in HTTP scripts. The first line declares an array of strings. That array is then used to hold the return value for http_find_values. Http_find_values searches on the current connection for specified values in the format (name, type, tag [, name, type, tag ... ]), where each set of name, type, tag specifies a single requested value. Up to 21 values can be requested in a call, and if any of the requested values can't be found, the corresponding element of the results array is "". The CHECK_FIND_RESULT macro validates returned values and supplies a default value for returned values of NULL.

In the code above, the second instance of the HTTP_REDIRECT_PREFIX tag will be stored in SgenRes_002 under the name RedirectPrefix. The CHECK_FIND_RESULT macro then checks to make sure the result returned is equal to "/developerworks/thankyou/". If an error is returned, the actual and expected results will be listed in the log.

Datapool values in emulation commands

Farther down in the script, you'll see this http_request command that has emulation functions embedded in it:

datapool values in emulation commands

In this code, datapool_value retrieves the value of the specified datapool column and returns it as a string. The values retrieved are the recorded values contained in the data_value arguments of the DATAPOOL_CONFIG statement at the end of the script. These values then get passed to the http_url_encode function. This function prepares the string for inclusion in the http_request command. In the code above, the values for the search fields are read and passed to the Web server. The datapool could be configured to send different search requests for each user.

Reference URI and URL

The next code snippet in the script stores the fully qualified URI (URL) accessed by the last GET or POST request in a string.

Reference URI and URL

In this code, the result of the http_request GET is stored in the string named SgenURI_022. Again, to make maintenance easier this variable could be given a more meaningful name. Just make sure you update the script everywhere this variable is referenced. You'll see a couple of calls like this in the script. Each of them is reestablishing the URI for the Web site.

Cookies

Finally, at the end of the script and just before the datapool information we looked at earlier, there's a section for cookie information.

section for cookie information

If you didn't clear your cookies before you recorded your session like I told you to, this block of code could be hundreds of lines long in your script. This is a listing of all the cookies on the computer at the time the session was recorded.

When you begin recording an HTTP session, TestManager queries your browser for any cookies it has stored. These cookies are loaded into memory during script playback, thus making playback more accurate with respect to initial cookie values. The cookies in the COOKIE_CACHE section are added to the user's cookie cache automatically before any commands in the script are executed. Cookies are created with expiration dates sufficiently far in the future to ensure that they won't have expired by the time you play back the script. This is important for sites that require certain cookies to function correctly. The two cookies listed above were created when the session was recorded.



Back to top


Designing a better performance test

The commands we just looked at in our sample script are representative of most of the commands you'll encounter when working with HTTP VU scripts. Understanding the code and what's happening in the script will help you better design your performance tests. For instance, once you understand how to find code that's validating graphics or JavaScript files, you can determine if it's critical to the test. Does it matter if my performance test fails on an image? If not, should I remove those calls to make the script more robust and easier to read and maintain?

There are many other strategies to simplify maintenance, as well. I would recommend doing the following:

  • Update variable names to add more meaning.
  • Add comments to mark key transactions.
  • Reformat the code to match the format of your other scripts.

If all else fails, steal a developer for a day and have him or her explain some of the HTTP to you and express concerns about what you should be testing.



Back to top


References and other resources

More information on HTTP can be found all over the Internet. MSDN is a good starting point. Check with your local developers for books or Web sites they use, as these will probably be the resources most relevant to the development happening on your project. If you need more help with the Rational tools, check developerWorks for white papers and articles, use online help, and become best friends with the VU Language Reference. Once you understand the makeup of the script and the technology you're testing, review some of the more advanced literature available on performance testing, including the "User Experience, Not Metrics" series and the "Beyond Performance Testing" series by Scott Barber.



About the author

Mike Kelly is currently a software testing consultant for the Computer Horizons Corporation in Indianapolis. He's had experience managing a software automation testing team and has been working with the Rational tools since 1999. His primary areas of interest are software development lifecycles, software test automation, and project management. Mike can be reached by e-mail.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top