session management in performance testing how-to
TRANSCRIPT
1
RadView Software How-to Session Management in Performance Testing The stateless nature of HTTP requires Internet application developers to find other methods of uniquely tracking a visitor through a web-based application. Various methods of managing a visitor’s session have been proposed and used, but the most popular method is through the use of
unique session IDs. Most web servers have ways of generating these session IDs automatically for the application developer. There are a few common ways in which these web servers communicate the session ID
between the client application (browser) and the web server, including stateless cookies, rewriting the URL and a hidden form field. In this document you will learn what is session management, how it
affects load testing and how to use WebLOAD for load testing sites which use session management techniques.
2
Table of Contents
Overview.....................................................................................................................3
What is Session management?..........................................................................3
IBM WebSphere session management .......................................................4
Microsoft ASP.NET session management...................................................5
Apache server .......................................................................................................5
Defining the problem .............................................................................................5
URL Rewriting recording sample ...................................................................6
Cookies recording sample ................................................................................7
How to overcome session management in our performance testing?7
Cookie-based session ........................................................................................7
URL Rewriting based session ..........................................................................8
Using Value Extraction building block .........................................................9
Hidden form based session .............................................................................9
Future enhancements..........................................................................................10
Resources .................................................................................................................10
Appendix – How does WebLOAD handle the Cookie header? .............11
3
Overview
The stateless nature of HTTP requires Internet application developers to find other methods of uniquely tracking a visitor through a web-based application. Various methods of managing a visitor’s session have been proposed and used, but the most popular method is through the use of unique session IDs. Most web servers have ways of generating these session IDs automatically for the application developer. There are a few common ways in which these web servers communicate the session ID between the client application (browser) and the web server, including stateless cookies, rewriting the URL and a hidden form field. This document provides information on how to use WebLOAD for load testing sites which use session management techniques.
What is Session management?
Session management refers to the way web servers and web applications track a given user’s interactions throughout their site pages while preserving their state between navigations. Due to the nature of HTTP, the protocol includes no built-in facility to uniquely identify or track a particular customer (or session) within an application without transmitting some data between the client and the server. Typically, the process of managing the state of a web-based client is through the use of session IDs. Session IDs are used by the application to uniquely identify a client browser, while background (server-side) processes are used to associate the session ID with the existing state of the user. Most common web servers have three methods available to both allocate and receive session ID information:
• The session ID information is embedded in the URL by the server, then received by the application on the following HTTP GET requests when the client clicks on links embedded within the page.
• The session ID information is stored within the fields of a form and submitted to the application. Typically the session ID information would be embedded within the form as a hidden field and submitted with the HTTP POST/GET command.
<FORM METHOD=POST ACTION=”/cgi-bin/news.pl”> <INPUT TYPE=”hidden” NAME=”sessionid” VALUE=”IE60012219”> <INPUT TYPE=”hidden” NAME=”allowed” VALUE=”true”> <INPUT TYPE=”submit” NAME=”Read News Article”>
4
• The session ID information is handled through the use of
cookies. When a request arrives at the server requiring that a
session be created, the server creates a session object,
associating it with a session ID. The session ID is transmitted
back to the
browser as
part of the
response
header and is
stored with
the rest of the
cookies in the
browser. On
subsequent
requests from
the browser,
the session ID
is transmitted as part of the request header, allowing the
application to associate each request for a given session ID with
prior requests from that user. The interaction between browser,
application server, and application are all handled transparently
to the end user and the application program. The application and
the user need not be, nor are they likely to be aware of the
session ID provided by the server.
IBM WebSphere session management
The IBM WebSphere application server (WAS) supports all of the above methods for session management but cookies are by far its preferred approach. The use of a cookie for tracking session state is the default in WAS. WAS implementation of this option differs from a pure cookie-based solution in that the WAS uses a single cookie named JSESSIONID that contains only the session ID. The JSESSIONID is used in turn by the server to associate the request with information already stored on the server for that session ID. By contrast, an entirely cookie-based solution would employ multiple cookies, each containing possibly sensitive user state information (account number, user ID, etc.). In an HTTP session, all attributes associated with the user's request are stored on the server. Since the only information transmitted between the server and the browser is the session ID cookie, which has a limited lifetime, an HTTP session can provide a much more secure mechanism than cookies can when configured in conjunction with SSL.
5
Microsoft ASP.NET session management
ASP uses HTTP cookies to send users their unique session keys. For example, an ASP application that uses sessions would respond to a user's request with an HTTP header such as:
Set-Cookie: ASPSESSIONID=PUYQGHUMEAAJPUYL; path=/Webapp
Each subsequent request by this browser to this server, in the virtual directory /Webapp, would include the HTTP cookie header:
Cookie: ASPSESSIONID=PUYQGHUMEAAJPUYL
Each active ASP.NET session is identified and tracked using a 120-bit SessionID string containing only the ASCII characters that are allowed in URLs. SessionID values are generated using an algorithm that guarantees uniqueness so that sessions do not collide, and randomness so that a malicious user cannot use a new SessionID to calculate the SessionID of an existing session. The SessionID strings are communicated across client-server requests either by means of an HTTP cookie or a modified URL with the SessionID string embedded, depending on how you configure the application settings.
Apache server
Apache server (version 1.3 and higher) includes a module named mod_usertrack, which uses cookies to identify a user's visit and then records access to the site identified by this unique ID. When the user first visits the site, a cookie with a unique ID is sent to them. This unique ID is kept until a predetermined timeout is reached so an individual's usage can be tracked on the server. It's not a complete solution, but it enables the identification of different individual users, even if they appear to come from the same IP address. With Apache server, the CookieName directive configures the name of the cookie that will be stored.
Defining the problem
Most of us use WebLOAD for load testing our internet applications mostly by submitting requests to the web server. What does this load testing process have to do with session management? The problem stems from two factors. The first is the virtual client testing model and the second is the record-replay authoring model. We will elaborate on both in this section. virtual client testing model 1– most professional load testing tools for
1 We should differentiate between Internet application load testing and network load testing,
Internet load testing tools such as WebLOAD support VC model which simulate a real user
behavior including state and think time, while other network load testing just push HTTP
transactions to the server. Although WebLOAD can be used for HTTP transaction generating, in
6
internet applications are based on the model of virtual client simulation on the protocol level. This means that the load generator simulates the client browser activity. This virtual browsing is perceived by the server as no different than a real user browsing the site. So we have N number of virtual users executing requests against the “session aware”, stateful internet web server. From a session management perspective, we have N different sessions opening and closing based on the virtual client activities. Record-Replay authoring model – Most load testing scripts are created by a QA professional using WebLOAD to record a template for the load test and later manipulate the script. The recording session is done by using the real client application, mostly the web browser, and browsing through the different web pages in the site. Here again, the tested site is not aware that a recording is taking place. Therefore, a session cookie is sent to the client or the URL containing the session ID as listed before. However, since the session is only valid as long as the browser is open, the test script contains a reference to a non valid session ID. If this script is played over, even in a debugging session it will fail since the original session was terminated.
URL Rewriting recording sample
The following code displays a session ID recorded while browsing our www.netizenbanking.com sample page:
/***** WLIDE - URL : http://www.netizenbanking.com/myAccountWelcome.asp?netizenSID=313321512732&ssn=demo&password=demo&I1.x=33&I1.y=11 - ID:6 *****/ wlHttp.Header["Referer"] = "http://www.netizenbanking.com/myAccountLogin.asp?netizenSID=31332151273" wlHttp.FormData["netizenSID"] = "31332151273" wlHttp.FormData["ssn"] = "demo" wlHttp.FormData["password"] = "demo" wlHttp.FormData["I1.x"] = "33" wlHttp.FormData["I1.y"] = "11" wlHttp.Get("http://www.netizenbanking.com/myAccountWelcome.asp")
today’s interactive internet application this is not enough and a VC model such as WebLOAD’s
should be used. 2 Although in this session the id is in a comment statement and has no effect on the agenda, it is
shown here for completeness purpose.
7
Note that in this sample the session ID is stored both in the netizenSID and in the Referer header. It is also important to note that although the netizenSID is part of the query string (see the recorded comment) WebLOAD knows to decode the string into form data, making it easy for the tester to parameterize it as needed.
Cookies recording sample
The following sample displays the session ID as recorded3 in a cookie against an ASP.NET sample page http://samples.gotdotnet.com/quickstart/aspplus/samples/apps/cookies1/VB/cookies1.aspx
***** WLIDE - URL :
http://samples.gotdotnet.com/quickstart/aspplus/samples/apps/cookies1/VB/cookies1.aspx - ID:2 *****/ wlGlobals.GetFrames = false wlHttp.Header["Accept"] = "\x2A/\x2A" wlHttp.Header["Accept-Language"] = "en-us,en;q=0.5" wlHttp.Header["UA-CPU"] = "x86" //wlHttp.Header["Accept-Encoding"] = "gzip, deflate" wlHttp.Header["User-Agent"] = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 1.1.4322; InfoPath.2)" wlHttp.Header["Host"] = "samples.gotdotnet.com" wlHttp.Header["Proxy-Connection"] = "Keep-Alive" wlHttp.Header["Pragma"] = "no-cache" wlHttp.Header["Cookie"] = "ASP.NET_SessionId=vbrffkvat1axj35545bx1a55; preferences1=ForeColor=black&BackColor=beige&LinkColor=blue&FontSize=8pt&FontName=Verdana" wlHttp.Get("http://samples.gotdotnet.com/quickstart/aspplus/samples/apps/cookies1/VB/cookies1.aspx")
The ASP.NET session ID is stored in a cookie named ASP.NET_SessionId. So far we reviewed the definition of session management and identified the issues we have to understand in order to build a load testing script for “session-aware” internet applications. In the next section we will review how to overcome this problem based on the specific technique implemented by your web server.
How to overcome session management in our performance
testing?
Cookie-based session
Most users testing a cookies-based session management application, will not see any problem while using WebLOAD because of the way it manages server side cookies. Depending on the “Script content” setting in the “Record Options” dialog, WebLOAD will record the different headers into the agenda, including the Cookie header. However, the Cookie header, as well as the content length header, are overwritten by the actual headers returned by the server during the playback mode (or
3 By default the Cookie header will not be recorded. If you want to see the recorded header you
have to change the Script content under the Record Options in the tools menu and select “check
the Record Headers”.
8
during the load execution mode as part of the load session in the console). For a detailed explanation of this process see the Appendix section in this document.
URL Rewriting based session
If your internet application is configured to use URL rewriting for session management, we will have to update the recorded agenda before we can debug it and execute it in a load session. The most common way to resolve this issue is by assigning the returned session ID to a local variable and use this variable later during the agenda. The modified agenda would look like the following:
/***** WLIDE - URL : http://localhost/netizen - ID:2 *****/ wlGlobals.GetFrames = false
wlHttp.Get("http://localhost/netizen") /***** WLIDE - Sleep - ID:3 *****/ Sleep(3843) /***** WLIDE - URL : http://localhost/netizen/myAccount.asp - ID:4 *****/ wlHttp.Header["Referer"] = "http://localhost/netizen/" wlHttp.Get("http://localhost/netizen/myAccount.asp") /***** WLIDE - BuildingBlock:ValueExtraction - ID:9 *****/ var sid = extractValue( "netizenSID=", "", document.links[0].search) InfoMessage("Extracted Session ID: " + sid) /***** WLIDE - Sleep - ID:5 *****/ Sleep(2000) /***** WLIDE - URL : http://localhost/netizen/myAccountLogin.asp?netizenSID=31332053076 - ID:6 *****/ wlHttp.Header["Referer"] = "http://localhost/netizen/myAccount.asp" wlHttp.FormData["netizenSID"] = sid // static value replaced by variable wlHttp.Get("http://localhost/netizen/myAccountLogin.asp") /***** WLIDE - Sleep - ID:7 *****/ Sleep(13516) /***** WLIDE - URL : http://localhost/netizen/myAccountWelcome.asp?netizenSID=31332053076&ssn=111111&password=22222222&I1.x=36&I1.y=9&I1=Submit - ID:8 *****/ wlHttp.Header["Referer"] = http://localhost/netizen/myAccountLogin.asp?netizenSID= + sid // static value replaced by variable wlHttp.FormData["netizenSID"] = sid // static value replaced by variable wlHttp.FormData["ssn"] = "111111" wlHttp.FormData["password"] = "22222222" wlHttp.FormData["I1.x"] = "36" wlHttp.FormData["I1.y"] = "9" wlHttp.FormData["I1"] = "Submit" wlHttp.Get("http://localhost/netizen/myAccountWelcome.asp")
While there are several ways to easily and efficiently update the agenda, the concept of the change process is the same: First, extract the value from the query string into a local variable. Then, perform a “search & replace” for the variable in the recorded agenda. In order to extract the value you can use a regular expression in JavaScript which is the scripting language used by WebLOAD. JavaScript 1.2 and later (also known as JScript, ECMAScript or ECMA-262) has built-in support for regular
9
expressions. In JavaScript, a regular expression is written in the form of /pattern/modifiers where "pattern" is the regular expression itself, and "modifiers" are a series of characters indicating various options. To test if the user entered a number, use: myString.match(/^\d+$/). /\d+/ matches any string containing one or more digits, but /^\d+$/ matches only strings consisting entirely of digits. To do a search and replace with regexes, use the string replace() method: myString.replace(/replaceme/g, "replacement"). Using the /g modifier makes sure that all
occurrences of "replaceme" are replaced. The second parameter is a normal string with the replacement text.
Using Value Extraction building block
If you don’t want to go into JavaScript regular expressions you can use the WebLOAD building block named Value Extraction in the LOAD section of the toolbox. All you have to do is drag the toolbox icon into the Agenda tree, and the Value Extraction building block parameters dialog box will appear. Fill in the prefix which is the sub string to look for. In our case it would be “NetizenSID=”, we don’t need a suffix here. In the Str field we will fill document.links[0].search, which is where the session ID is passed. Lastly, the return value (retVarName) is the name of the variable we want to use for storing the session id. For our example we used sid.
Hidden form based session
The process of handling session ID issues inside the recorded script for applications using the hidden form method is very similar to the way we handled the URL rewriting method in the previous section. Most likely it will even be a bit easier since it is much easier to extract the value from the hidden form field by just referring to the field by name using the document.Form collection. We will use our NetizenBanking sample application again, this time clicking on the
10
“apply for a credit card” which uses a hidden form field named netizenSID to store the session ID. The modified agenda would look like this:
/***** WLIDE - URL : http://localhost/netizen - ID:2 *****/
wlGlobals.GetFrames = false wlHttp.Get("http://localhost/netizen") /***** WLIDE - Sleep - ID:3 *****/ Sleep(4718) /***** WLIDE - URL : http://localhost/netizen/cardApply.asp - ID:4 *****/ wlHttp.Header["Referer"] = "http://localhost/netizen/" wlHttp.Get("http://localhost/netizen/cardApply.asp") /***** WLIDE - Extracting Session ID - ID:7 *****/ // here the session id is stored in the form hidden field named "netizenSID" var sid = document.forms[0]["netizenSID"].value InfoMessage("Extracted Session ID: " + sid) /***** WLIDE - Sleep - ID:5 *****/ Sleep(23469) /***** WLIDE - URL : http://localhost/netizen/cardConfirm.asp?first=Nachum&mi=&last=Dimer&address=Some+Address&city=Jerusalem&state=&zip=&email=&homephone=&employment=Employed+Full-time&workphone=&income=&netizenSID=62888961201&I1.x=18&I1.y=10&I1=Submit - ID:6 *****/ wlHttp.Header["Referer"] = "http://localhost/netizen/cardApply.asp" wlHttp.FormData["first"] = "Nachum" wlHttp.FormData["mi"] = "$WL$EMPTY$STRING$" wlHttp.FormData["last"] = "Dimer" wlHttp.FormData["address"] = "Some Address" wlHttp.FormData["city"] = "Jerusalem" wlHttp.FormData["state"] = "$WL$EMPTY$STRING$" wlHttp.FormData["zip"] = "$WL$EMPTY$STRING$" wlHttp.FormData["email"] = "$WL$EMPTY$STRING$" wlHttp.FormData["homephone"] = "$WL$EMPTY$STRING$" wlHttp.FormData["employment"] = "Employed Full-time" wlHttp.FormData["workphone"] = "$WL$EMPTY$STRING$" wlHttp.FormData["income"] = "$WL$EMPTY$STRING$" wlHttp.FormData["netizenSID"] = sid // static data is replaced by variable wlHttp.FormData["I1.x"] = "18" wlHttp.FormData["I1.y"] = "10" wlHttp.FormData["I1"] = "Submit"
wlHttp.Get("http://localhost/netizen/cardConfirm.asp")
Future enhancements
In this document we learned what session management is and how load testing is affected by it. As we explained in chapter 0 it is quite easy to
update the agenda to work with session-aware sites. However, keeping QA professional productivity in mind we expect to make your life even easier. Future versions of WebLOAD might include additional features such as Smart Copy & Paste and a correlation engine.
Resources
1. Apache server http://www.serverwatch.com/tutorials/article.php/3588671
2. ASP.NET http://msdn.microsoft.com/library/en-us/cpguide/html/cpconsessionstate.asp?frame=true
11
3. IBM WebSphere http://www.informit.com/articles/article.asp?p=332851&seqNu
m=2&rl=1
4. http://www.technicalinfo.net/papers/WebBasedSessionManagement.html
Appendix – How does WebLOAD handle the Cookie header?
The following code sample is taken from a recording of the ASP.NET site (http://samples.gotdotnet.com/quickstart/aspplus/samples/apps/cookies1/VB/cookies1.aspx) . As you can see in the recording, after the Record Headers was checked in the Script Content tab of the Record options, WebLOAD recorded the Header “Cookie” (wlHttp.Header["Cookie"] = "ASP.NET_SessionId=tjx0tjvaf3ynio452wong4eb;), note that this was only passed in the second URL in the site. In the first URL, the web site generated a new session ID for us and passed it back to the client in the Cookie.
/***** WLIDE - URL : http://samples.gotdotnet.com/quickstart/aspplus/samples/apps/cookies1/VB/cookies1.aspx - ID:2 *****/ wlGlobals.GetFrames = false wlHttp.Header["Accept"] = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, \x2A/\x2A" wlHttp.Header["Accept-Language"] = "en-us,en;q=0.5" wlHttp.Header["UA-CPU"] = "x86" //wlHttp.Header["Accept-Encoding"] = "gzip, deflate" wlHttp.Header["User-Agent"] = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 1.1.4322; InfoPath.2)"
wlHttp.Header["Host"] = "samples.gotdotnet.com" wlHttp.Header["Proxy-Connection"] = "Keep-Alive" wlHttp.Get("http://samples.gotdotnet.com/quickstart/aspplus/samples/apps/cookies1/VB/cookies1.aspx") /***** WLIDE - Sleep - ID:3 *****/ Sleep(9251) /***** WLIDE - URL : http://samples.gotdotnet.com/quickstart/aspplus/samples/apps/cookies1/VB/customize.aspx - ID:4 *****/ wlHttp.Header["Accept"] = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, \x2A/\x2A" wlHttp.Header["Referer"] = "http://samples.gotdotnet.com/quickstart/aspplus/samples/apps/cookies1/VB/cookies1.aspx" wlHttp.Header["Accept-Language"] = "en-us,en;q=0.5" wlHttp.Header["UA-CPU"] = "x86" //wlHttp.Header["Accept-Encoding"] = "gzip, deflate" wlHttp.Header["User-Agent"] = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 1.1.4322; InfoPath.2)" wlHttp.Header["Proxy-Connection"] = "Keep-Alive" wlHttp.Header["Host"] = "samples.gotdotnet.com" wlHttp.Header["Cookie"] = "ASP.NET_SessionId=tjx0tjvaf3ynio452wong4eb; preferences1=ForeColor=black&BackColor=beige&LinkColor=blue&FontSize=8pt&FontName=Verdana" wlHttp.Get("http://samples.gotdotnet.com/quickstart/aspplus/samples/apps/cookies1/VB/customize.aspx")
Also note that the session ID we got in the recording phase is tjx0tjvaf3ynio452wong4eb.
12
Now, let’s play the agenda in debug mode and see what happens. We start by visiting the first page. Since this is our first page in the site, the server generated a new session ID for us and sent it back to the client. Now we move to the second request, although the agenda set the Cookie to "ASP.NET_SessionId=tjx0tjvaf3ynio452wong4eb;” the engine parses the cookies header and replaces the header with the one we just got from the server during the playback mode.
This can be seen clearly in the HTTP Header Viewer. Note that the value of the ASP.NET_SessionId has changed from the original in the agenda. Note that this behavior is not a bug. WebLOAD parses the Cookie header and replaces the values as needed. If you want to manually change the cookie from within your agenda code you can use the wlCookie object for that. The following sample code uses the wlCookie to set a cookie.
//Set a cookie
wlCookie.Set("CUSTOMER", "JOHN_SMITH", "www.ABCDEF.com", "/", "Wed, 08-Apr-98 17:29:00 GMT") //WebLOAD submits the cookie wlHttp.Get("www.ABCDEF.com/products/OrderForm.cgi") //Delete the cookie wlCookie.ClearAll()
13
Contact Information: North America RadView Software Inc.
991 Highway 22 West Suite 200 Bridgewater, NJ 08807
Email: [email protected] Phone:908-526-7756 Fax:908-864-8099
Toll Free:1-888-RadView
United Kingdom RadView Software (UK) Email: [email protected]
Phone: +44-080-81011165
Other Countries RadView Software Ltd. 14 Hamelacha Street
Rosh Haayin 48091, Israel Phone:+972-3-915-7060 Fax:+972-3-915-7683
RadView corporate website: www.radview.com
WebLOAD community website: www.webload.org