By Chris Muir | Article Rating: |
|
May 8, 2010 07:34 AM EDT | Reads: |
359 |

Sometime back I blogged about Stress & load testing web applications (even ADF & Apex) using Apache JMeter. That post dealt with the generic setup of recording a web session and then replaying under load via JMeter.
When considering using JMeter for JDeveloper 11g ADF applications there are additional JMeter configuration steps required beyond that detailed in the original post. As per the original post ADF passes around cookies to store the JSESSIONID, and you can use JMeter's HTTP Cookie Manager to correctly handle the cookie. However ADF also makes use of a number of parameters passed as HTTP POST parameters and URL parameters. On running an ADF application you'll often see URL parameters like _adf.ctrl-state, _afrLoop, and embedded within the HTTP bodies variables such as javax.faces.ViewState, used by ADF to coordinate state with the browser session. In order for JMeter to simulate multiple user sessions it needs to be correctly configured to handle these too, capturing and carrying the unique values for each session in the load test.
The following post lists the additional configurations required for JMeter beyond those described in the original post. As noted in the original post the easiest way to setup your JMeter Test Plan is to record an existing ADF session through JMeter's HTTP Proxy Server and I haven't bothered to reiterate those instructions here. In turn I've taken no effort to explain the JMeter features we're utilizing to do this; if you want to learn about the relevant JMeter features consult the JMeter User Manual.
Caveat for ADF 10g users: You'll note above I specifically stated JDeveloper 11g ADF, not 10g. I haven't tested any of the following settings for JDev 10g and I don't believe they'll work, as if memory serves me correctly the POST and URL parameters mechanisms changed between versions. However the following notes may give you enough information to dig around in a running 10g ADF application, looking at the HTTP Requests to work out what parameters to work with.
JMeter ADF Required Configurations
The following lists five additional objects and their settings. You need only create one of each for each Thread Group. The end result will look something like this:
a) HTTP Cookie Manager
Create via Test Plan -> Thread Group -> Right Click -> Add -> Config Element -> HTTP Cookie Manager
Name: | HTTP Cookie Manager |
Clear cookies each iteration: | Selected |
b) User Defined Variables
Create via Test Plan -> Thread Group -> Right Click -> Add -> Config Element -> User Defined Variables
Name: | ADF Variables |
Variable Name: | afrLoop |
Variable Name: | afrWindowId |
Variable Name: | jsessionId |
Variable Name: | adf.ctrl-state |
Variable Name: | javax.faces.ViewState |
No initial values.
c) Regular Expression Extractor #1
Create via Test Plan -> Thread Group -> Right Click -> Add -> Post Processors -> Regular Expression Extractor
Name: | adf.ctrl-state Extractor |
Response Field to Check: | Body |
Reference Name: | adf.ctrl-state |
Regular Expression: | _adf.ctrl-state=([-_0-9A-Za-z!]{10,13}) |
Template: | $1$ |
Match No.: | 1 |
Default Value: | n/a |
Take notice that the variable name does not include an underscore in it's name unlike the actual parameter _adf.ctrl-state.
d) Regular Expression Extractor #2
Create via Test Plan -> Thread Group -> Right Click -> Add -> Post Processors -> Regular Expression Extractor
Name: | afrLoop Extractor |
Response Field to Check: | Body |
Reference Name: | afrLoop |
Regular Expression: | _afrLoop=([-_0-9A-Za-z]{13,16}) |
Template: | $1$ |
Match No.: | 1 |
Default Value: | n/a |
Take notice that the variable name does not include an underscore in it's name unlike the actual parameter _afrLoop.
d) Regular Expression Extractor #3
Create via Test Plan -> Thread Group -> Right Click -> Add -> Post Processors -> Regular Expression Extractor
Name: | afrWindowId Extractor |
Response Field to Check: | Body |
Reference Name: | afrWindowId |
Regular Expression: | window.name='([-_0-9A-Za-z!]{10,13})' |
Template: | $1$ |
Match No.: | 1 |
Default Value: | n/a |
e) Regular Expression Extractor #4
Create via Test Plan -> Thread Group -> Right Click -> Add -> Post Processors -> Regular Expression Extractor
Name: | javax.faces.ViewState Extractor |
Response Field to Check: | Body |
Reference Name: | javax.faces.ViewState |
Regular Expression: | <input type="hidden" name="javax\.faces\.ViewState" value="!(.+?)"> |
Template: | $1$ |
Match No.: | 1 |
Default Value: | n/a |
f) Regular Expression Extractor #5
Create via Test Plan -> Thread Group -> Right Click -> Add -> Post Processors -> Regular Expression Extractor
Name: | jsesssionId Extractor |
Response Field to Check: | Body |
Reference Name: | jsessionId |
Regular Expression: | ;jsessionid=([-_0-9A-Za-z!]{63}) |
Template: | $1$ |
Match No.: | 1 |
Default Value: | n/a |
Recorded HTTP Request Changes
After recording an ADF session in JMeter, and setting up the variables above, you'll note in the recorded HTTP Requests numerous references to the same named variables as HTTP parameters. Yet the recorded HTTP Requests include the parameters' values for the recorded session, which simply won't work when we replay the session as the values will have changed.
It is therefore necessary to identify all locations where the parameters exist in the recorded session HTTP Requests and substitute references to your variables.
a) HTTP Request – Path – any path that makes reference to jsessionId must be changed.
ie: /SageApp/faces/ViewEvents;jsessionId=${jsessionId}
b) HTTP Request – Path – ditto any path that makes reference to _adf.ctrl-state must be changed.
ie. /SageApp/faces/ViewEvents?_adf.ctrl-state=${adf.ctrl-state}
You can also change this in the name if you want but it wont make a different to the overall result, the name is for show only.
c) HTTP Request – Parameters – for any of the following parameters:
_adf.ctrl-state
_afrLoop
_afrWindowId (* see exception at the end of this step)
...for their values substitute the relevant variable. The following example shows the values for the afrLoop and adf.ctrl-state replaced:
However there is one exception with _afrWindowId. In one of the initial requests its value will be the literal string "null" (see the picture in step (a) for an example). Do not replace this, leave it as null.
d) HTTP Request – Parameters – for the "javax.faces.ViewState" parameter, ditto replace its values. Note it is necessary to put a not (negate) symbol in front of it:
ie. !${javax.faces.ViewState}
In addition by default the "Encode?" parameter will be on for each javax.faces.ViewState. Instead turn it off for each:
e) HTTP Request – Parameters – for the "unique" parameter, occurring in the Path and request parameters replace it with the following notation:
${__javaScript(new Date().getTime(),DUMMY)}
Note there is no JMeter user variable for this, we just write it straight into the unique value.
f) HTTP Header Manager Referer – if the HTTP session has been recorded via JMeter's HTTP Proxy, each HTTP Request will include a sub-element HTTP Header Manager that includes an element called Referer. You'll note it will have hardcoded many of the parameters discussed above. However I don't think ADF requires the Referer element and you can just ignore it or delete it from every HTTP Header Manager.
Assertions
Once you've completed the above setup and want to run your load test via JMeter, it is important to see that the test is working correctly. One way to do this is to create a View Results Tree (Test Plan -> Thread Group -> Right Click -> Add -> Listener -> View Results Tree) that allows you to inspect the response of each HTTP Request. If you then see HTTP Request responses in red this indicates a HTTP error code response (!= 200). However it's also necessary to inspect each response even if they are green to see if there's a valid response returned carrying an error message. There is definitely a small knack to differentiating between the different type of failures in an ADF application, which you'll become familiar with on some experience.
In order to save you having to look for the same problems for each test-run, you can create a Response Assertion (Test Plan -> Thread Group -> Add -> Assertions -> Response Assertion) to look for specific errors in the responses. From my own ADF experience you want to setup a Response Assertion with the following values:
Which Samples to Test: | Main Sample Only |
Response Field to Test: | Text Response |
Pattern Matching Rules: | Contains |
Not: | Selected |
Patterns to Test #1: | The following exception occurred |
Patterns to Test #2: | Server Exception during PPR |
Patterns to Test #3: | ADFC-12000 |
Patterns to Test #4: | java.net.SocketException |
Patterns to Test #5: | java.io.IOException |
This isn't a definitive list, and in turn there may be specific errors that you may want to pick up for your application.
Sample JMeter file
Readers can download a sample JMeter JMX file for ADF here with the configurations already setup.
Finishing Comment
I haven't had the chance to test this in every ADF scenario or application. It's possible in your application, dependent on the components you're using or some other trick of ADF, that I've missed one of the state values it wants the browser to carry. With the post above hopefully you'll get an idea of the majority and be able to identify more. I'd appreciate it if anybody finds more that we need to cater for please post a comment with your findings to assist other readers.
Read the original blog entry...
Published May 8, 2010 Reads 359
Copyright © 2010 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Chris Muir
Chris Muir, an Oracle ACE Director, senior developer and trainer, and frequent blogger at http://one-size-doesnt-fit-all.blogspot.com, has been hacking away as an Oracle consultant with Australia's SAGE Computing Services for too many years. Taking a pragmatic approach to all things Oracle, Chris has more recently earned battle scars with JDeveloper, Apex, OID and web services, and has some very old war-wounds from a dark and dim past with Forms, Reports and even Designer 100% generation. He is a frequent presenter and contributor to the local Australian Oracle User Group scene, as well as a contributor to international user group magazines such as the IOUG and UKOUG.
- An Exclusive Interview with Oracle, Cloud Expo 2010 Diamond Sponsor
- The Next Chapter in the Virtualization Story Begins
- Unveiling the java.lang.Out OfMemoryError
- Cloud Computing Bootcamp Returns to Cloud Expo in New York April 20, 2010
- Is MySQL Doomed to Extinction?
- Gosling Out of Oracle
- Gosling Hints He Left Oracle over Money
- 101 on jQuery Selector Performance
- It's the Java vs. C++ Shootout Revisited!
- Bravo, Google!
- Novell Owns Unix
- Leveraging Public Clouds to SaaS-Enable Enterprise Applications
- An Exclusive Interview with Oracle, Cloud Expo 2010 Diamond Sponsor
- The Next Chapter in the Virtualization Story Begins
- The End of IT 1.0 As We Know It Has Begun
- Unveiling the java.lang.Out OfMemoryError
- HTML5 Web Sockets: A Quantum Leap in Scalability for the Web
- Cloud Computing Bootcamp Returns to Cloud Expo in New York April 20, 2010
- Is MySQL Doomed to Extinction?
- Chuck Phillips Was Supposed to Become CEO of CA
- Gosling Out of Oracle
- Gosling Hints He Left Oracle over Money
- 101 on jQuery Selector Performance
- It's the Java vs. C++ Shootout Revisited!
- A Cup of AJAX? Nay, Just Regular Java Please
- Java Developer's Journal Exclusive: 2006 "JDJ Editors' Choice" Awards
- The i-Technology Right Stuff
- JavaServer Faces (JSF) vs Struts
- Rich Internet Applications with Adobe Flex 2 and Java
- Java vs C++ "Shootout" Revisited
- Bean-Managed Persistence Using a Proxy List
- Reporting Made Easy with JasperReports and Hibernate
- Creating a Pet Store Application with JavaServer Faces, Spring, and Hibernate
- What's New in Eclipse?
- Why Do 'Cool Kids' Choose Ruby or PHP to Build Websites Instead of Java?
- i-Technology Predictions for 2007: Where's It All Headed?