'Continual Full GC',I will KILL you...
Updated:
Root Cause: when using Axis as an implementation of the SOAP, when Web Service request coming with the attachment over 1MB, then it will make trouble with Heap Memory.
Lot of OOM issues after searching on the web, and no ideal solution with that right now on Apache Axis:
1. SAX2EventRecorder causes Out of memory during Deserialization https://issues.apache.org/jira/browse/AXIS-2698
2. SAX2EventRecorder throws Out of Memory exception during Deserialization https://issues.apache.org/jira/browse/AXIS-2749
Solution:Just Replace the Apache Axis which project has been suspended for quite long time since 2006.
Take Away:
1. When you find Memory Heap Issues, you need to get HeapDump as possible as you can, the other info can be useless... We use SendSingal.exe(for Windows) to trigger the JDK5 to get the Heapdump, when we noticed the Continual Full GC
2. Analysis HeapDump file together with Functional QA, they can give some idea from business perspective, in order to reproduce your issue on local much easier.
After reproducing the issue, then you will solve your pain sooner or later, there will be something wrong with your code :)
Monday, December 20, 2010
Tuesday, December 14, 2010
Track my Performance Data with WebDriver test by MongoDB
In my WebDriver test, I will always track performance data during automation test on daily bases, it helps to reuse automation scripts which QA team donated to track slowness cases, and guarantee the test coverage very well.
Here is a sample tracking diagram (X-axis: Date, Y-axis: Response time):
Meanwhile, the data is End-End response time,not only back-end html generation time, which load testing tool usually measures.
Testing Code:
MongoDBReader source code:
MongoDB Shell console:
Here is a sample tracking diagram (X-axis: Date, Y-axis: Response time):
Meanwhile, the data is End-End response time,not only back-end html generation time, which load testing tool usually measures.
Testing Code:
MongoDBReader conn = new MongoDBReader();
WebDriver driver = new FirefoxDriver();
long starttime = new Date().getTime();
driver.get("http://www.google.com/");
conn.InstertPermLog(starttime, "Landing_Page");
driver.close();
MongoDBReader source code:
import java.net.UnknownHostException;
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
/* sample usage
* MongoDBReader conn = new MongoDBReader();
* ...
* long starttime = new Date().getTime();
* driver.get("http://www.google.com/");
* conn.InstertPermLog(starttime, "Landing_Page");
*/
public class MongoDBReader {
private DB db;
private DBCollection coll;
public MongoDBReader(String hostname) throws UnknownHostException, MongoException{
// Connect to Mongo DB server
Mongo m = new Mongo( hostname );
// Get Mongo DB Connection
db = m.getDB("perfdb");
// Prepare Collection
coll = db.getCollection("perfTestColl");
}
public MongoDBReader() throws UnknownHostException, MongoException {
//Connect to the localhost MongoDB by Default
String hostname = "localhost";
// Connect to Mongo DB server
Mongo m = new Mongo( hostname );
// Get Mongo DB Connection
db = m.getDB("perfdb");
// Prepare Collection
coll = db.getCollection("perfTestColl");
}
public DB getDB(){
return db;
}
public DBCollection getCollection(){
return coll;
}
public void InstertPermLog(long startTime, String transactionName){
long endtime = new java.util.Date().getTime();
long responsetime = endtime - startTime;
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.S");
Date date = new Date();
BasicDBObject doc = new BasicDBObject();
doc.put("TimeStamp", dateFormat.format(date));
doc.put("Rtime", responsetime);
doc.put("transaction", transactionName);
coll.insert(doc);
}
}
MongoDB Shell console:
> db.perfTestColl.find();
{ "_id" : ObjectId("4d078fbb3599030f8a412be1"), "TimeStamp" : "2010/12/14 23:39:
39.546", "Rtime" : NumberLong(4609), "transaction" : "Landing_Page" }
{ "_id" : ObjectId("4d078fc33599030f8b412be1"), "TimeStamp" : "2010/12/14 23:39:
47.953", "Rtime" : NumberLong(1641), "transaction" : "Landing_Page" }
{ "_id" : ObjectId("4d078fcb3599030f8c412be1"), "TimeStamp" : "2010/12/14 23:39:
55.578", "Rtime" : NumberLong(1360), "transaction" : "Landing_Page" }
Wednesday, December 08, 2010
O'Reilly Velocity China 2010
I am starting to do Performance Testing since 2006. And I have followed Steve about Front-end Performance optimization from 2007, although i am mainly focus on the testing and back-end tuning at most of time.
A big Fan of him, because always can get many fresh ideas and best practices after reading his blog, if you haven't read his blog, suggest to catch up with it :) (Seems twitter has become his major updated place right now...)
A big Fan of him, because always can get many fresh ideas and best practices after reading his blog, if you haven't read his blog, suggest to catch up with it :) (Seems twitter has become his major updated place right now...)
Thursday, November 25, 2010
Sorting algorithm in Perl
My Girl Friend likes the language that easy to write but hard to read, just like Perl which makes me crazy :)
Here are 3 simple examples which is illustrating her algorithm basic skills(BTW, she is a math talented person i ever met during college)
Insertion Sorting:
Bubble Sorting:
Here are 3 simple examples which is illustrating her algorithm basic skills(BTW, she is a math talented person i ever met during college)
Insertion Sorting:
@arry1 = (12,32,3,25,67,24,56);
@arry2 = shift @arry1;
$j=$#arry2;
foreach $arry (@arry1){
if ($arry2[$j]<= $arry) {
push @arry2, $arry;
}
elsif ($j==0 ) {
unshift @arry2, $arry;
}
else {
foreach (reverse(@arry2)){
if ($_ > $arry){
$j-=1;
}
}
if ($j >=0){
$i = $j+1;
@arry2= (@arry2[0..$j], $arry, @arry2[$i..$#arry2]);
}
else {
unshift @arry2, $arry;
}
}
$j=$#arry2;
}
foreach (@arry2){
print "$_ ";
}
Quick Sorting: @arry1=(12,32,3,25,67,24,56);
$i=0;
$j=$#arry1;
&quick_sorting($i,$j);
sub quick_sorting {
my($m,$n)= @_;
while ($m <$n){
if ($arry1[$m]<= $arry1[$n]) {
$n-=1;
}
else {
($arry1[$m], $arry1[$n]) = ($arry1[$n], $arry1[$m]);
$m+=1;
}
}
if ($m - $_[0]> 1) {
&quick_sorting($_[0], $m-1);
}
if ($_[1] -$n > 1){
&quick_sorting($n+1, $_[1]);
}
}
foreach $arry (@arry1){
print "$arry\n";
}
Bubble Sorting:
@arry1 = (12,32,3,25,67,24,56);
$i=0;
$j=$#arry1;
for ( ; $j >=0; $j-=1){
for ($i=0; $i<$j; $i+=1 ){
if ($arry1[$i]-$arry1[$i+1] gt 0) {
($arry1[$i], $arry1[$i+1])=($arry1[$i+1], $arry1[$i]);
}
}
}
foreach $arry (@arry1){
print "$arry\n";
}
Wednesday, November 24, 2010
Aggregate Jmeter Raw data into CSV file
I am doing daily automated Jmeter load test to track performance trend using command line, due to only raw data available , so i need to write some code to parser and Aggregate it.
PS: I am using Ruby1.9 to handle this, Ruby1.8.7 and below do not implement the append row to CSV file yet.
You need to Modify the settings for Results file configuration in jmeter.properties in advance:
Ruby Source code:
Testing code:
Enjoy!
PS: I am using Ruby1.9 to handle this, Ruby1.8.7 and below do not implement the append row to CSV file yet.
You need to Modify the settings for Results file configuration in jmeter.properties in advance:
jmeter.save.saveservice.output_format=csv
jmeter.save.saveservice.assertion_results=none
jmeter.save.saveservice.data_type=false
jmeter.save.saveservice.label=true
jmeter.save.saveservice.response_code=true
jmeter.save.saveservice.response_data=false
jmeter.save.saveservice.response_data.on_error=false
jmeter.save.saveservice.response_message=false
jmeter.save.saveservice.successful=false
jmeter.save.saveservice.thread_name=true
jmeter.save.saveservice.time=true
jmeter.save.saveservice.subresults=false
jmeter.save.saveservice.assertions=false
jmeter.save.saveservice.latency=true
jmeter.save.saveservice.samplerData=false
jmeter.save.saveservice.responseHeaders=false
jmeter.save.saveservice.requestHeaders=false
jmeter.save.saveservice.encoding=false
jmeter.save.saveservice.bytes=true
jmeter.save.saveservice.url=false
jmeter.save.saveservice.filename=false
jmeter.save.saveservice.hostname=false
jmeter.save.saveservice.thread_counts=false
jmeter.save.saveservice.sample_count=false
jmeter.save.saveservice.idle_time=false
jmeter.save.saveservice.print_field_names=false
Ruby Source code:
require 'csv'
require 'time'
#Generate agg result from Jmeter raw data
def parserCSVperfdata(filename)
h = {};
h_count = {}
result = [];
i =0;
CSV.foreach(filename) do |rec|
if (h.has_key?(rec[2]))
h[rec[2]] = h[rec[2]].to_i + rec[1].to_i
h_count[rec[2]] = h_count[rec[2]].to_i + 1
next;
else
h[rec[2]] = rec[1]
h_count[rec[2]] = h_count[rec[2]].to_i + 1
end
end
h.each_key { |key|
h[key] = h[key].to_i/h_count[key].to_i
result[i] = key;
result[i+1] = ",";
result[i+2] = h[key];
result[i+3] = "\n";
i=i+4
}
return h.sort;
end
#insert agg result into target CSV file
def insertlog(src,dest)
# get current date and collect the data today
t = Time.now
cdate = t.strftime("%Y-%m-%d")
#append row to CSV file, using Ruby1.9 here for mode = 'a'
csvwriter = CSV.open(dest,'a')
#append array of string, need to convert date string to array
csvwriter << cdate.split
src.each do |row|
csvwriter << row
end
end
Testing code:
t = Time.now
mdate = t.strftime("%Y%m%d")
aggresultfile = "D://Perf//loadtest.csv";
singlethreadresultfile = "D://Perf//singleuser.csv"
# Generate JMeter agg result on daily bases
arraydir = Dir.entries("D://tools//jakarta-jmeter-2.4//bin");
arraydir.each { |item|
item.scan(/#{mdate}_[0-9]+_rawdata\.csv/) { |match|
aggdata = parserCSVperfdata("D://tools//jakarta-jmeter-2.4//bin//#{match}");
insertlog(aggdata,aggresultfile);
}
}
Enjoy!
Monday, November 22, 2010
Set current date and time variable in Batch file
Check your system date format at first:
It might be different from other computer, some of are put weekday in the front of the date:
Here we take 11/23/2010 Tue as an example:
PS: no space between ‘=’ and ‘%’, it costs me 10 mins around this...
The current date is: 11/23/2010 Tueso the format is mm/dd/yyyy weekday
It might be different from other computer, some of are put weekday in the front of the date:
The current date is: Tue 11/23/2010
Here we take 11/23/2010 Tue as an example:
@echo off
SET inputdate=%date:~6,4%%date:~0,2%%date:~3,2%
SET inputtime=%time:~0,2%%time:~3,2%%time:~6,2%
echo %inputdate%_%inputtime%_Rawdata.jtl
Output:20101122_234425_Rawdata.jtl
PS: no space between ‘=’ and ‘%’, it costs me 10 mins around this...
Thursday, November 11, 2010
How to attach add-ons to your FirefoxDirver
A Typical sample like this, in case i forget how to do :)
Another Sample is to set proxy for the FirefoxDriver:
//Pre-condition: Right Clicking the button to save the add-on to some location
final String firebugPath = "C:\\addon-1843-latest.xpi";
FirefoxProfile profile = new FirefoxProfile();
profile.addExtension(new File(firebugPath));
WebDriver driver = new FirefoxDriver(profile);
Another Sample is to set proxy for the FirefoxDriver:
FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("network.proxy.http", "YourDomain");
profile.setPreference("network.proxy.http_port", port);
profile.setPreference("network.proxy.type", 1);
profile.setPreference("network.proxy.share_proxy_settings", true);
WebDriver driver = new FirefoxDriver(profile);
Friday, November 05, 2010
Find the Difference
Ruby is cool, it can write some code like this:
Or if you want to practice your head, you can type the code like me :
arrayA = ['a345','v123','765','b666', '333', 'aaaa'];
arrayB = ['234','b666','777','v123','c123'];
puts arrayA - arrayB;
puts arrayB - arrayA;
Or if you want to practice your head, you can type the code like me :
def getdiff( array1, array2)
array1.sort!
array2.sort!
a = array1.pop
b = array2.pop
while (a != nil && b!= nil)
if a == b
a = array1.pop
b = array2.pop
next;
elsif a < b
puts b;
b = array2.pop();
next;
elsif a > b
puts a;
a = array1.pop();
next;
end
end
while(b == nil && a != nil)
puts a
a = array1.pop();
end
while(a == nil && b != nil)
puts b
b = array2.pop();
end
puts "Mission complete!"
end
arrayA = ['a345','v123','765','b666', '333', 'aaaa'];
arrayB = ['234','b666','777','v123','c123'];
getdiff(arrayA, arrayB);
Thursday, November 04, 2010
Using WebDriver and Dynatrace-Ajax to help your Performance test
I have WebDriver Automation test suite in place, So i do not want to create new scripts like Watir or Selenium to do performance test with dynatrace-ajax, just like this post by Watir : http://blog.dynatrace.com/2009/11/04/5-steps-to-automate-browser-performance-analysis-with-watir-and-dynatrace-ajax-edition/
or This one by Selenium 1.0: http://blog.dynatrace.com/2010/05/21/how-to-use-your-selenium-tests-for-automated-javascriptajax-performance-analysis/
I have created Raft which is a Automation fixture by integrating WebDriver with TestNG to help to Automation Test : https://github.com/joychester/Raft/wiki
So I can use WebDriver scripts to help with Performance sanity test now, which save a lot of effort to find out performance problem in early stage and also reuse the scripts already created by QA team :)
First you need to launch Dynatrace-ajax client from : Start-> All Programs-> dynatrace-> dynatrace Ajax Edition
Then you need to add "DT_IE_XXX" Environment Variables to start your test.
This is my Runnner.bat file to start my WebDriver tests:
Here is a Sample test script:
PS: Here i am using Raft's own method newWebDriverPlusInstance() which can load different browser Type to do your test.
Here is a screen shot of Dynatrace-ajax summary generated by my WebDriver test:
Enjoy!
or This one by Selenium 1.0: http://blog.dynatrace.com/2010/05/21/how-to-use-your-selenium-tests-for-automated-javascriptajax-performance-analysis/
I have created Raft which is a Automation fixture by integrating WebDriver with TestNG to help to Automation Test : https://github.com/joychester/Raft/wiki
So I can use WebDriver scripts to help with Performance sanity test now, which save a lot of effort to find out performance problem in early stage and also reuse the scripts already created by QA team :)
First you need to launch Dynatrace-ajax client from : Start-> All Programs-> dynatrace-> dynatrace Ajax Edition
Then you need to add "DT_IE_XXX" Environment Variables to start your test.
This is my Runnner.bat file to start my WebDriver tests:
@echo off
set DT_IE_AGENT_ACTIVE=true
set DT_IE_SESSION_NAME=dynaTrace_Automation
java -cp ..\Classes;..\lib\*; raft.engine.TestEngine > log.txt
Here is a Sample test script:
@Test(priority = 4)
public void aTest3() throws InterruptedException{
WebDriverPlus driver = WebDriverPlus.newWebDriverPlusInstance("IE");
//InternetExplorerDriver driver = new InternetExplorerDriver();
Thread.sleep(2000);
driver.get("http://www.google.com/");
Thread.sleep(2000);
driver.findElement(By.name("q")).sendKeys("dynatrace");
Thread.sleep(2000);
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("_dt_addMark(\"start_search\")");
driver.findElement(By.name("btnG")).click();
js.executeScript("_dt_addMark(\"end_search\")");
System.out.println("Its Test3");
driver.quit();
}
PS: Here i am using Raft's own method newWebDriverPlusInstance() which can load different browser Type to do your test.
WebDriverPlus driver = WebDriverPlus.newWebDriverPlusInstance("IE");
Of course, you can use InternetExplorerDriver directly in sample code which is commented.Here is a screen shot of Dynatrace-ajax summary generated by my WebDriver test:
Enjoy!
Wednesday, November 03, 2010
Please help to vote Issue 835 of WebDriver
My teammate Jersey found this bug:"click() does not work when the link is wrapped in two lines"
http://code.google.com/p/selenium/issues/detail?id=941
However, there is a duplicate issue there: http://code.google.com/p/selenium/issues/detail?id=835
So please help to vote for this issue and make it get fixed ASAP :)
http://code.google.com/p/selenium/issues/detail?id=941
However, there is a duplicate issue there: http://code.google.com/p/selenium/issues/detail?id=835
So please help to vote for this issue and make it get fixed ASAP :)
Monday, October 18, 2010
Asking PageFactory.initElements() for Help
Some people asked me what kind of things are done by PageFactory.initElements()?
Let's see a simple example to see the difference,PS: code just for Demo, not for formal testing:-):
CommonPage.class(PageObject)
Version1, using PageFactory.initElements(WebDriver, Class):
Testcode:
Version2, just using New:
Testcode:
So both PageFactory.initElements(driver, CommonPage.class); and new CommonPage(driver); are calling the construct method in order to pass the Driver to Commonpage class.
The difference between these 2 versions is to initialize looking up the WebElement (Fields) you declared in Commonpage.
so if you define your WebElements using @FindBy annotation instead of defining it within your each method directly(eg. driver.findElement(By)), then you need to using PageFactory.initElements() for help.
Let's see a simple example to see the difference,PS: code just for Demo, not for formal testing:-):
CommonPage.class(PageObject)
public class CommonPage {
private WebDriver driver;
@FindBy(how = How.NAME, using = "q")
private WebElement searchtext;
@FindBy(how = How.NAME, using = "btnG")
private WebElement searchbutton;
public CommonPage(WebDriver driver) {
this.driver = driver;
System.out.println("cool stuff!");
}
public CommonPage getpages(){
driver.get("http://www.google.com/");
searchtext.sendKeys("hello, common");
return this;
}
public void searchaction(){
searchbutton.click();
}
}
Version1, using PageFactory.initElements(WebDriver, Class):
Testcode:
public class PageFactoryTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
WebDriver driver = new FirefoxDriver();
CommonPage searchpage = PageFactory.initElements(driver, CommonPage.class);
searchpage.getpages().searchaction();
driver.quit();
}
}
Version2, just using New:
Testcode:
public class PageFactoryTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
WebDriver driver = new FirefoxDriver();
CommonPage searchpage = new CommonPage(driver);
searchpage.getpages().searchaction();
driver.quit();
}
}
So both PageFactory.initElements(driver, CommonPage.class); and new CommonPage(driver); are calling the construct method in order to pass the Driver to Commonpage class.
The difference between these 2 versions is to initialize looking up the WebElement (Fields) you declared in Commonpage.
so if you define your WebElements using @FindBy annotation instead of defining it within your each method directly(eg. driver.findElement(By)), then you need to using PageFactory.initElements() for help.
Tuesday, October 12, 2010
Windows OS performance measurements by 'typeperf' in Ruby
I am writing a Windows resource monitoring script with ‘typeperf’ command in Ruby, so that i can centralize to get all my testing server's OS Health status during performance testing.
I simply get measurements like CPU%, Mem utlization, Disk I/O throughput and Network I/O throughput from Perfmon Counters.
perf_mon_util.rb Class Source code:
Perf_mon_runner.rb source code:
How to use it in command-line:
Real Usage sample:
PS: The Monitoring result will write in the file path as .CSV format by default.
i am using Gruff to draw the graph of monitoring result:
the code is pretty straightforward:
will consider to add : \\System\\Processor Queue Length to monitor the Queue length:
An instantaneous count of threads that are in the processor queue.
I simply get measurements like CPU%, Mem utlization, Disk I/O throughput and Network I/O throughput from Perfmon Counters.
perf_mon_util.rb Class Source code:
class PerfMonUtil
@hostIPs = [];
def initialize(hostarray)
hostarray = hostarray.sub(/\s/, '');
@hostIPs = hostarray.split(',');
puts "monitor IP(s): " + @hostIPs * ",";
end
# the unit of duration is set to minutes by default
def perfmon(duration = 5,intv = 1, filepath = "C:\\temp_mon\\")
puts @hostIPs;
puts intv;
sampler_count = (duration.to_i * 60) / intv.to_i;
@hostIPs.each { |inputIP|
machineIP = inputIP.strip;
filename = filepath + machineIP.gsub(/\./,'_') + "-" + Time.now.strftime("%Y%m%d-%H%M%S");
Thread.new {
system("typeperf",
"\\processor(_total)\\% processor time", #CPU%
"\\processor(_total)\\% user time",
"\\processor(_total)\\% privileged time",
"\\Memory\\Available Kbytes", #MEM_Utilization
"\\physicaldisk(_total)\\% disk read time", #DISK I/O
"\\physicaldisk(_total)\\% disk write time",
"\\network interface(*#1)\\bytes total/sec", #NetWork I/O
"-s", "#{machineIP}","-si","#{intv}", "-sc", "#{sampler_count}", "-o", filename)
Process.exit!(1);
}
}
end
end
Perf_mon_runner.rb source code:
require 'perf_mon_util'
case ARGV.length
when 0
puts "Please assign monitored machines' name, you can access help by type Perf_mon_runner.rb -help"
puts "Process exiting..."
Process.exit!(1);
when 1
if ARGV[0] == "-help"
puts "usage samples listed: Perf_mon_runner.rb MonitredIPs Duration Interval FilePath"
puts "Perf_mon_runner.rb \"ip1,ip2,ip3\" 1 20 \"D:\\\\temp\\\\\""
puts "Monitoring object list(Measurements including):"
puts " \\processor(_total)\\% processor time"
puts " \\processor(_total)\\% user time"
puts " \\processor(_total)\\% privileged time"
puts " \\Memory\\Available Kbytes"
puts " \\physicaldisk(_total)\\% disk read time"
puts " \\physicaldisk(_total)\\% disk write time"
puts " \\network interface(*#1)\\bytes total/sec"
Process.exit!(1);
end
puts "put your monitoring files in C:\\temp_mon\\"
CPU_Utilization= PerfMonUtil.new(ARGV[0]);
CPU_Utilization.perfmon();
when 2
puts "put your monitoring files in C:\\temp_mon\\"
CPU_Utilization= PerfMonUtil.new(ARGV[0]);
CPU_Utilization.perfmon(ARGV[1]);
when 3
puts "put your monitoring files in C:\\temp_mon\\"
CPU_Utilization= PerfMonUtil.new(ARGV[0]);
CPU_Utilization.perfmon(ARGV[1],ARGV[2]);
when 4
puts "put your monitoring files in " + ARGV[3]
CPU_Utilization= PerfMonUtil.new(ARGV[0]);
CPU_Utilization.perfmon(ARGV[1],ARGV[2],ARGV[3]);
end
How to use it in command-line:
Perf_mon_runner.rb ["YourIP1,YourIP2"] [Monitor_Duration] [Sample_Interval] [FilePath]
Real Usage sample:
Perf_mon_runner.rb "YourIP1,YourIP2" 1 20 "D:\\temp\\"
PS: The Monitoring result will write in the file path as .CSV format by default.
i am using Gruff to draw the graph of monitoring result:
the code is pretty straightforward:
require 'csv'
require 'gruff'
def parserperfmon(csvfile,targetfile)
arraycpu = Array.new;
i = 0;
CSV.foreach(csvfile) do |rec|
# CPU% data is put into arraycpu
arraycpu[i] = rec[1]
i = i+1;
end
#column title is removed
arraycpu.shift
#String need to be converted to float type in arraycpu
arraycpu.collect! { |item|
item.to_f
}
g = Gruff::Line.new
g.title = "CPU% Monitoring Graph";
g.data("CPU%", arraycpu)
g.write(targetfile)
end
filename = "D:\\TEMP\\10_201_10_173-20101125-153102\.csv"
targetname ="D:\\TEMP\\perf_mon.png"
parserperfmon(filename,targetname);
will consider to add : \\System\\Processor Queue Length to monitor the Queue length:
An instantaneous count of threads that are in the processor queue.
Saturday, October 09, 2010
A Hangzhou Trip
A bird's eye-view of West LakeOn the top of the hill
I like the smile face in the middle :-) The question is who did that...
"Taking look at my tail, i am changing the color"
Friday, October 08, 2010
Raft Flow Chart
I Draw my Raft automation framework flow chart using "TheBrain" Application, here it is:
http://webbrain.com/u/11J0
http://webbrain.com/u/11J0
Sunday, September 26, 2010
Create WaterFall Chart for Performance (Duration)
usually, I wanna know how much load created at certain point of time on my async system, and see how much impact the concurrent load bring to it. So I made a simple Create WaterFall Chart to help me to understand these more clearly.
This is written in Ruby,sorry java guys, it is faster for me to write ruby code than java, but i like java gradually :-)
I am using Google Chart API, Googlecharts, TinyURL services, Thanks you for providing these!
A quick snapshot for waterfall chart(click to see big):
Test code:
Prepare Google chart Data and para:
Get Google Chart URL:
Minify URL using tinyURL:
Also if you have written a data query method to get start and end time from DB, then it is easy to get startArray and endArray directly by T-SQL. i am using this in practice: http://snippets.dzone.com/posts/show/3906
or you may take look at this, FYI:
Usage sample:
This is written in Ruby,sorry java guys, it is faster for me to write ruby code than java, but i like java gradually :-)
I am using Google Chart API, Googlecharts, TinyURL services, Thanks you for providing these!
A quick snapshot for waterfall chart(click to see big):
Test code:
require 'gchart'
require 'time'
require 'open-uri'
require 'uri'
require 'accessDB'
#Get start and end time stamp from DB
startArray = ["2010-09-26 16:58:37.693","2010-09-26 16:58:38.223","2010-09-26 16:58:38.833",
"2010-09-26 16:58:39.600","2010-09-26 16:58:40.210","2010-09-26 16:58:40.833","2010-09-26 16:58:55.740"];
endArray = ["2010-09-26 16:59:56.543","2010-09-26 16:59:58.183","2010-09-26 17:00:04.217",
"2010-09-26 17:00:09.370","2010-09-26 17:00:10.217","2010-09-26 17:00:19.323","2010-09-26 17:00:25.027"];
Gchart_string = prepareData(startArray, endArray )
Gchart_url = waterFallUrl(Gchart_string)
puts minifyUrl(Gchart_url)
Prepare Google chart Data and para:
def prepareData(starttime, endtime )
if starttime.length > 400
puts "\nExceed the maxium number(400) of records."
puts "You can try to split them to display.Press Enter to exit..."; $stdout.flush
gets
break;
end
# convert Time Object string to Time object Int
starttime.collect! { |time1|
Time.parse("#{time1}").to_i;
}
starttime.sort!
endtime.collect! { |time2|
Time.parse("#{time2}").to_i;
}
endtime.sort!
# prepare data in array, convert to string used by Gchart
flag = starttime[0]
starttime.collect! { |time1|
time1-flag;
}
endtime.collect! { |time2|
time2-flag;
}
if endtime.last > 3600
puts "\nWarning: Duration is too long to display well for Chart(3600s is recommended).";
puts "You can split the data to display."
end
line_xy_string = "";
scale_num = 1;
cata = 10;
while endtime.last > cata
cata = cata + 10 ;
end
scale_num = cata/starttime.length
starttime.length.times { |i|
line_xy_string << starttime[i].to_s;
line_xy_string << ",";
line_xy_string << endtime[i].to_s;
line_xy_string << "|";
line_xy_string << ((i+1)*scale_num).to_s + "," + ((i+1)*scale_num).to_s;
# ignore the last "|"
if ((i+1) < starttime.length)
line_xy_string << "|";
end
}
line_xy_string << "&chds=";
line_xy_string << "0,#{cata}";
line_xy_string << "&chxt=x,x,y"
line_xy_string << "&chxr=0,0,#{cata}"
line_xy_string << "&chxl=1:|Duration(sec)"
return line_xy_string;
end
Get Google Chart URL:
def waterFallUrl(chart_string)
output_url = Gchart.line_xy(:size => '700x400',
:title => "WaterFall Charts",
:custom => "chd=t:#{chart_string}")
#"&chxr=0,0" is automatic added to the end of string,
#remove it due to already identify one in chart_string
output_url.chomp!("&chxr=0,0");
return output_url
end
Minify URL using tinyURL:
def minifyUrl(gchartUrl)
# convert URL to escaped one
escaped_url = URI.escape(gchartUrl, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
short_url = open("http://tinyurl.com/api-create.php?url=#{escaped_url}").read
return short_url;
end
Also if you have written a data query method to get start and end time from DB, then it is easy to get startArray and endArray directly by T-SQL. i am using this in practice: http://snippets.dzone.com/posts/show/3906
or you may take look at this, FYI:
require 'win32ole'
class SQLServer
# This class manages database connection and queries
attr_accessor :connection, :data, :fields
attr_writer :username, :password
def initialize(host, username = 'sa', password='sa')
@connection = nil
@data = nil
@host = host
@username = username
@password = password
end
def open(database)
# Open ADO connection to the SQL Server database
connection_string = "Provider=SQLOLEDB.1;" #SQLOLEDB.1,SQLNCLI
connection_string << "Persist Security Info=False;"
connection_string << "User ID=#{@username};"
connection_string << "password=#{@password};"
connection_string << "Initial Catalog=#{database};"
connection_string << "Data Source=#{@host};"
connection_string << "Network Library=dbmssocn"
@connection = WIN32OLE.new('ADODB.Connection')
@connection.Open(connection_string)
end
def query(sql)
# Create an instance of an ADO Recordset
recordset = WIN32OLE.new('ADODB.Recordset')
# Open the recordset, using an SQL statement and the
# existing ADO connection
recordset.Open(sql, @connection)
# Create and populate an array of field names
@fields = []
recordset.Fields.each do |field|
@fields << field.Name
end
begin
# Move to the first record/row, if any exist
recordset.MoveFirst
# Grab all records
@data = recordset.GetRows
rescue
@data = []
end
recordset.Close
# An ADO Recordset's GetRows method returns an array
# of columns, so we'll use the transpose method to
# convert it to an array of rows
@data = @data.transpose
end
def close
@connection.Close
end
end
Usage sample:
db = SQLServer.new('YourDBIP', 'sa', 'sa')
sp = db.open('DBName')
startArray = db.query("select * from somewhere where ...")
endArray = db.query("sselect * from somewhere where ...")
db.close
Monday, September 20, 2010
Handle Datepicker using WebDriver simple sample
Someone asked me: "How to identify a datepicker on the webpage, which will display after clicking the datepicker icon?"
Here is a simple sample, you can customize your own function for reading your web page source and make a api for picking any dates freely :-)
//Find all the Calendar on the Web Page
List<WebElement> Datepickers = driver.findElements(By.className("CalendarIcon"));
//Trigger the calendar of StartDate
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
Datepickers.get(0).click();
WebElement table = driver.findElement(By.className("ui-datepicker-calendar"));
List<WebElement> tds = table.findElements(By.tagName("td"));
for (WebElement td: tds){
//Select 20th Date of current month
if (td.getText().equals("20")){
td.findElement(By.linkText("20")).click();
break;
}
}
//Trigger the calendar of EndDate
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
Datepickers.get(1).click();
WebElement table2 = driver.findElement(By.className("ui-datepicker-calendar"));
List<WebElement> tds2 = table2.findElements(By.tagName("td"));
for (WebElement td2: tds2){
//Select 22th Date of current month
if (td2.getText().equals("22")){
td2.findElement(By.linkText("22")).click();
break;
}
}
Here is a simple sample, you can customize your own function for reading your web page source and make a api for picking any dates freely :-)
//Find all the Calendar on the Web Page
List<WebElement> Datepickers = driver.findElements(By.className("CalendarIcon"));
//Trigger the calendar of StartDate
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
Datepickers.get(0).click();
WebElement table = driver.findElement(By.className("ui-datepicker-calendar"));
List<WebElement> tds = table.findElements(By.tagName("td"));
for (WebElement td: tds){
//Select 20th Date of current month
if (td.getText().equals("20")){
td.findElement(By.linkText("20")).click();
break;
}
}
//Trigger the calendar of EndDate
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
Datepickers.get(1).click();
WebElement table2 = driver.findElement(By.className("ui-datepicker-calendar"));
List<WebElement> tds2 = table2.findElements(By.tagName("td"));
for (WebElement td2: tds2){
//Select 22th Date of current month
if (td2.getText().equals("22")){
td2.findElement(By.linkText("22")).click();
break;
}
}
Wednesday, September 15, 2010
Table walk through in WebDriver
Very Simple sample for dealing with table elements on webPage in WebDriver:
WebElement table = driver.findElement(By.name("meetingRoomTable"));
//findout all checkboxes within the table
List<WebElement> checkboxes = table.findElements(By.cssSelector("input[type=\"checkbox\"]"));
if (!checkboxes.isEmpty()){
for (WebElement checkbox : checkboxes){
if(!checkbox.isSelected()){
checkbox.toggle();
}
}
System.out.println("all checkboxes elements checked now");
}
else
System.out.println("no checkbox elements exsit on this table");
Sunday, September 12, 2010
Distribute your test suites by STAF(STAX)
STAF is a good Open source "test automation" framework which developed by IBM. I am currently using STAF(STAX) to distribute my test Suites which are organized by TestNG, it is improve your efficiency.
Here is a simple sample how I zip, transfer and execute My Test on 2 machines(please format this XML by yourself, if you need to look at it):
PS: you may need to modify your under STAF/bin/, so that it can avoid some restrictions.
Here is a simple sample how I zip, transfer and execute My Test on 2 machines(please format this XML by yourself, if you need to look at it):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE stax SYSTEM "stax.dtd">
<!-- New document created with EditiX at Fri Jul 09 15:35:49 CST 2010 -->
<stax>
<script>machinelist = ['Machinename1','Machinename2']</script>
<defaultcall function="ZipTest"></defaultcall>
<function name="ZipTest">
<sequence>
<stafcmd>
<location>'localhost'</location>
<service>'zip'</service>
<request>'ADD ZIPFILE D:/Raft_Project/TestPlan.zip DIRECTORY D:/Raft_Project/TestPlan RECURSE RELATIVETO D:/Raft_Project' </request>
</stafcmd>
<call function="'sleep'"></call>
<call function="'DistributionTest'"></call>
<call function="'sleep'"></call>
<call function="'CleanupTest'"></call>
</sequence>
</function>
<function name="DistributionTest">
<paralleliterate var="machinename" in="machinelist">
<sequence>
<stafcmd>
<location>machinename</location>
<service>'fs'</service>
<request>'DELETE ENTRY D:/Raft_Project/TestPlan RECURSE CONFIRM' </request>
</stafcmd>
<call function="'sleep'"></call>
<stafcmd>
<location>'local'</location>
<service>'fs'</service>
<request>'COPY FILE D:/Raft_Project/TestPlan.zip TODIRECTORY D:/Raft_Project/ TOMACHINE %s' % machinename </request>
</stafcmd>
<call function="'sleep'"></call>
<stafcmd>
<location>machinename</location>
<service>'zip'</service>
<request>'UNZIP ZIPFILE D:/Raft_Project/TestPlan.zip TODIRECTORY D:/Raft_Project/'</request>
</stafcmd>
<call function="'sleep'"></call>
<stafcmd>
<location>machinename</location>
<service>'fs'</service>
<request>'DELETE ENTRY D:/Raft_Project/TestPlan.zip RECURSE CONFIRM'</request>
</stafcmd>
<process>
<location>machinename</location>
<command mode='"shell"'>'Runner.bat'</command>
<workdir>R'D:\Raft_Project\TestPlan\TestRunner_Module1'</workdir>
<returnstdout/>
<returnstderr/>
</process>
</sequence>
</paralleliterate>
</function>
<function name="CleanupTest">
<stafcmd>
<location>'localhost'</location>
<service>'fs'</service>
<request>'DELETE ENTRY D:/Raft_Project/TestPlan.zip RECURSE CONFIRM'</request>
</stafcmd>
</function>
<function name="sleep">
<stafcmd>
<location>'localhost'</location>
<service>'delay'</service>
<request>'delay 6000'</request>
</stafcmd>
</function>
</stax>
hope it helps! More detail instruction, please go to STAF official website:http://staf.sourceforge.net/PS: you may need to modify your
# Turn on tracing of internal errors and deprecated options
trace enable tracepoints "error deprecated"
# Enable TCP/IP connections
interface ssl library STAFTCP option Secure=Yes option Port=6550
interface tcp library STAFTCP option Secure=No option Port=6500
# Set default local trust
#trust machine local://local level 5
trust default level 5
# Add default service loader
serviceloader library STAFDSLS
SERVICE STAX LIBRARY JSTAF EXECUTE \
D:/STAF/services/stax/STAX.jar OPTION J2=-Xmx384m
SERVICE EVENT LIBRARY JSTAF EXECUTE \
D:/STAF/services/stax/STAFEvent.jar
SET MAXQUEUESIZE 10000
SERVICE Cron LIBRARY JSTAF EXECUTE D:\STAF\services\cron\STAFCron.jar
WebDriver Wait is easier after using implicitlyWait()
"WebDriver will wait until the page has fully loaded (that is, the "onload" event has fired) before returning control to your test or script."
The classic example is Javascript starting to run after the page has loaded (onload); while if the website is very "rich", it is always hard for WebDriver to identify some elements by its own blocking API.
Previous solution mentioned/suggested by experts are : Use the Wait class to wait for a specific element to appear:http://groups.google.com/group/webdriver/browse_thread/thread/50c963cd25fb416c/61aae67b8a2560fd?#61aae67b8a2560fd
Here is one example, which i wrapped the presenceOfElementLocated():
My test code:
This way looks a little bit fussy to me, although it works well.
Now, implicitlyWait() gives tests a "KISS" and most importantly, it did solve the problem.
You may notice that the first sample code using wait.until(), you have to two wait.until() for each link element, otherwise the code will fail; While the second one, you just add one implicitlyWait() in front of the "Buzz" link.
I do not know why, but it shows that implicitlyWait() is a better choice for locating (ajax) elements.
PS: I marked "in front of" as bold above, which means implicitlyWait() is a kind of registration method, you need to tell Webdriver in advance.
The classic example is Javascript starting to run after the page has loaded (onload); while if the website is very "rich", it is always hard for WebDriver to identify some elements by its own blocking API.
Previous solution mentioned/suggested by experts are : Use the Wait class to wait for a specific element to appear:http://groups.google.com/group/webdriver/browse_thread/thread/50c963cd25fb416c/61aae67b8a2560fd?#61aae67b8a2560fd
Here is one example, which i wrapped the presenceOfElementLocated():
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
import com.google.common.base.Function;
public class MyWaiter {
private WebDriver driver;
public MyWaiter(WebDriver driver){
this.driver = driver;
}
public WebElement waitForMe(By locatorname, int timeout){
WebDriverWait wait = new WebDriverWait(driver, timeout);
return wait.until(MyWaiter.presenceOfElementLocated(locatorname));
}
public static Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {
// TODO Auto-generated method stub
return new Function<WebDriver, WebElement>() {
@Override
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
};
}
}
My test code:
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
driver.get("http://www.google.com/");
MyWaiter myWaiter = new MyWaiter(driver);
WebElement search = myWaiter.waitForMe(By.name("btnG"), 10);
search.click();
}
This way looks a little bit fussy to me, although it works well.
Now, implicitlyWait() gives tests a "KISS" and most importantly, it did solve the problem.
driver.findElement(By.id("signIn")).click();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.switchTo().frame("canvas_frame");
driver.findElement(By.partialLinkText("Buzz")).click();
driver.findElement(By.linkText("Cheng Chi")).click();
You may notice that the first sample code using wait.until(), you have to two wait.until() for each link element, otherwise the code will fail; While the second one, you just add one implicitlyWait() in front of the "Buzz" link.
I do not know why, but it shows that implicitlyWait() is a better choice for locating (ajax) elements.
PS: I marked "in front of" as bold above, which means implicitlyWait() is a kind of registration method, you need to tell Webdriver in advance.
Thursday, September 02, 2010
Check and Set Isolation level in SQL Server
Check isolation level:
Default Isolation level in SQL Server is "READ COMMITTED", Once you want to change it:
For example, Set isolation level to READ UNCOMMITTED:
DBCC useroptions
Default Isolation level in SQL Server is "READ COMMITTED", Once you want to change it:
For example, Set isolation level to READ UNCOMMITTED:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
Wednesday, September 01, 2010
Switching Frame and Windows in WebDriver sample code
1> Switch to different Frames:
Notice when you set the frame index, it starts with 0 for the first frame:
2> Switch to different Windows:
Writing a common function based you own app for switching will be more helpful for your Code Clean!
List<WebElement> frameset = driver.findElements(By.tagName("frame"));
if(frameset.size()>0) {
for (WebElement framename : frameset){
System.out.println("frameid: " + framename.getAttribute("name"));
}
}
else System.out.println("can not find any frame in HTML");
Notice when you set the frame index, it starts with 0 for the first frame:
driver.switchTo().frame(0);
2> Switch to different Windows:
Set<string> handlers = driver.getWindowHandles();
if (driver.getWindowHandles().size()>= 1){
for(String handler : handlers){
driver.switchTo().window(handler);
if (driver.getCurrentUrl().contains("Popup")){
System.out.println("Get focus on Popup window");
break;
}
}
}
else System.out.println("No windows founded!");
Writing a common function based you own app for switching will be more helpful for your Code Clean!
Thursday, August 12, 2010
Wednesday, August 11, 2010
Deal with Javascript alert( ) and confrim( ) in WebDriver, as workaround
I posted one blog about Deal with "JS div DialogPane in WebDriver":
http://joychester.blogspot.com/2010/07/js-alert-handling-with-webdriver.html
Currently I met more dialog on different kind of page to deal with
<1> Javascript alert(msg)::
Most of time, I meet this situation when there is a validation on Front end. If you have to deal with this situation, one way to disable alert, before you click on a button which trigger the alert(), so that alert will not be triggered, while the validation always be there:
<2> Javascript confrim(msg):
Here I will post an example how to simulate pressing "OK" button to deal with confirmation dialog.
First, find out the JavaScript which is sending a confirmation message by sniffer tool:
Then, you may need to execute such bellowing javascript to simulate pressing "OK" button:
instead of simple click() which will trigger the confirmation dialog:
<3> The easiest Walkround:
I like the post on the Watir Wiki, which introduce "the Simplest way to stop JavaScript Pop Ups", the idea can be borrowed from that:
http://wiki.openqa.org/display/WTR/JavaScript+Pop+Ups
Hope this helpful!
Update:
WebDriver-Beta1 will have an implementation of the Alerts and Prompts API for the FirefoxDriver :)
http://joychester.blogspot.com/2010/07/js-alert-handling-with-webdriver.html
Currently I met more dialog on different kind of page to deal with
<1> Javascript alert(msg)::
Most of time, I meet this situation when there is a validation on Front end. If you have to deal with this situation, one way to disable alert, before you click on a button which trigger the alert(), so that alert will not be triggered, while the validation always be there:
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("window.alert = function(msg){};");
button.click();
<2> Javascript confrim(msg):
Here I will post an example how to simulate pressing "OK" button to deal with confirmation dialog.
First, find out the JavaScript which is sending a confirmation message by sniffer tool:
confirmed = confirm("Warning! This account is currently in use. Would you like to continue to login?");
if (confirmed)
{
this.document.forms[0].submitAction.value = "TERMINATE";
this.document.forms[0].submit();
}
else
{
this.document.forms[0].submitAction.value = "ABORT";
this.document.forms[0].submit();
}
function doSubmit(url, submitAction){
document.forms[0].action = url;
document.forms[0].target = "_self";
document.forms[0].submitAction.value = submitAction;
document.forms[0].submit();
}
Then, you may need to execute such bellowing javascript to simulate pressing "OK" button:
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("javascript:doSubmit('/app/login.do','TERMINATE');");
instead of simple click() which will trigger the confirmation dialog:
login.click();
<3> The easiest Walkround:
I like the post on the Watir Wiki, which introduce "the Simplest way to stop JavaScript Pop Ups", the idea can be borrowed from that:
http://wiki.openqa.org/display/WTR/JavaScript+Pop+Ups
Hope this helpful!
Update:
WebDriver-Beta1 will have an implementation of the Alerts and Prompts API for the FirefoxDriver :)
Monday, August 02, 2010
calculate performance by datediff() and aggregation() functions
As we store Raw data in our Database, which just history record without any calculation, just log start timestamp and end timestamp of each action/method. So here is a sample on how to calculate performance by datediff() and aggregation() functions:
declare @starttime varchar(50)
declare @endtime varchar(50)
set @starttime='03/08/2010 10:25:00.000'
set @endtime='03/08/2010 12:00:00.000'
select count(*), avg(datediff(millisecond,starttime, endtime)), min(datediff(millisecond,starttime, endtime)), max(datediff(millisecond,starttime, endtime))
from statistics_log
where event_type='send' and starttime > @starttime and starttime < @endtime
Thursday, July 22, 2010
Deal with JS div DialogPane in WebDriver
Updated: Another related post on js alert and confirmation stuff on http://joychester.blogspot.com/2010/08/deal-with-javascript-alert-and-confrim.html
During my testing, I met one "Send" link which will trigger js DialogPane to get your confirmation, such "OK" or "Cancel", onclick will execute JavaScript function like this for "OK" :
Here is a sample code how I simulate clicking "OK" within the js DialogPane:
Thanks for Shawn's Demo code, she gives me really great suggestion and inspiration!! :)
During my testing, I met one "Send" link which will trigger js DialogPane to get your confirmation, such "OK" or "Cancel", onclick will execute JavaScript function like this for "OK" :
onclick="confirmSend()"
Here is a sample code how I simulate clicking "OK" within the js DialogPane:
driver.switchTo().activeElement();
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("confirmSend()");
Thanks for Shawn's Demo code, she gives me really great suggestion and inspiration!! :)
Friday, July 16, 2010
Take screen shot on WebDriver
Simple code on take screen shot on WebDriver(InternetExplorerDriver,FirefoxDriver and ChromeDriver):
FirefoxDriver driver = new FirefoxDriver();
....
File pngFile = new File("D:\\test\\", "shot.png");
File tmpFile = driver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(tmpFile, pngFile);
Thursday, July 15, 2010
Get WebElement within PageFactory class by refelction
I just wandering how to get PageFactory's private WebElements in another test method?
Here is the code which Vance Zhao provided a way to find WebElements by reflection:
Here is the PageObjects code:
I will not consider to do this kind of coding in our test code , it is really a “Demo code”.
I will try to Abstract public methods in PageObjects Class which is a really worth stuff to do and make testing more fun and challenging! And also consider make WebElement to public as a workaround :)
Here is the code which Vance Zhao provided a way to find WebElements by reflection:
......
FSILoginPage landingpage =
PageFactory.initElements(driver, LoginPage.class);
Field f = landingpage.getClass().getDeclaredField("username");
WebElement e = new DefaultElementLocator(driver, f).findElement();
e.sendKeys("123456");
.....
Here is the PageObjects code:
public class LoginPage {
private WebElement username;
......
I will not consider to do this kind of coding in our test code , it is really a “Demo code”.
I will try to Abstract public methods in PageObjects Class which is a really worth stuff to do and make testing more fun and challenging! And also consider make WebElement to public as a workaround :)
The fast way to locate page elements on PageFactory
From PageFactory.java source code, it has a demo that without @FindBy annotation, it will find page element using Xpath by default, which is a Clean and Smart way, however not a fast way:
So from performance perspective, I will be glad to use @FindBy annotation way:
public class Page {
private WebElement submit;
}
there will be an element that can be located using the xpath expression
"//*[@id='submit']" or "//*[@name='submit']"
So from performance perspective, I will be glad to use @FindBy annotation way:
public class Page {
@FindBy(How.ID_OR_NAME, using="submit")
private WebElement loginbutton;
}
Tuesday, July 13, 2010
Emulating selenium APIs within WebDriver
Emulating selenium APIs within WebDriver which allows for the WebDriver and Selenium APIs to live side-by-side, a simple sample FYI:
WebDriver driver = new FirefoxDriver();
driver.get("http://www.google.com.hk/");
//PageObjects design pattern
GoogleSearchPage googlesearchpage =
PageFactory.initElements(driver, GoogleSearchPage.class);
String baseUrl = driver.getCurrentUrl();
//Change into Selenium instance
Selenium selenium = new WebDriverBackedSelenium(driver, baseUrl);
//Using selenium method
selenium.type("q", "Gmail");
selenium.click("btnG");
//using PageObjects and driver
googlesearchpage.clearsearchtext(driver);
googlesearchpage.searchfor(driver, "joychester");
//change back to Webdriver instance
WebDriver driverInstance =
((WebDriverBackedSelenium)selenium).getUnderlyingWebDriver();
googlesearchpage.clearsearchtext(driver);
googlesearchpage.searchfor(driverInstance, "Gmail");
//close browser and stop selenium
driverInstance.close();
selenium.stop();
Quit completely when emulating Selenium API in WebDriver
Once you Emulating Selenium API in WebDriver code, you need to quit your service like this separately:
driverInstance.close();
selenium.stop();
driverInstance.close();
selenium.stop();
......
String baseUrl = driver.getCurrentUrl();
Selenium selenium = new WebDriverBackedSelenium(driver, baseUrl);
selenium.open("http://www.google.com.hk/");
WebDriver driverInstance =
((WebDriverBackedSelenium)selenium).getUnderlyingWebDriver();
googlesearchpage.searchfor(driverInstance, "Gmail");
driverInstance.close();
selenium.stop();
......
"Make it Small, Do it Clean"
Saturday, June 12, 2010
String match using Regular expression in both Java and Ruby
sometimes, I will looking for some dynamic data/elements from HTMLsource to make my automation scripts more robust and reliable, so using regular expression to do string match is very useful for me to get them:
Example in Java( for selenium usage):
Example in Ruby( for Watir usage):
Love Ruby, it is simple :)
Example in Java( for selenium usage):
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexTestHarness {
public static void main(String[] args){
Pattern pattern =
Pattern.compile("information-abc-([0-9]+)");
Matcher matcher =
pattern.matcher("information-abc-9887234-information-abc-223333889-information-abc-12233");
while (matcher.find()) {
for (int i=1; i<=matcher.groupCount(); i++) {
String groupStr = matcher.group(i);
System.out.println(groupStr);
}
}
}
}
Example in Ruby( for Watir usage):
def regex_match(search_pattern)
source_string = "information-abc-9887234-information-abc-223333889-information-abc-12233";
source_string.scan(/#{search_pattern}/) { |match| puts match;}
end
regex_match("information-abc-([0-9]+)");
Love Ruby, it is simple :)
Friday, June 11, 2010
World CUP 2010 , Right here, Right now!
Two talented team i will support:
- Argentina
- Mexico
Let's enjoy the Game from Today!:)
- Argentina
- Mexico
Let's enjoy the Game from Today!:)
Wednesday, June 09, 2010
SoapUI MockOperation Dispatching in Groovy script
SoapUI provides several ways to dispatch mock service response, you can find the detail information from: http://www.soapui.org/Service-Mocking/simulating-complex-behaviour.html.
If you want to manage your mock response dispatch more flexible, then the Script way is your choice.
Here is the sample script you can select your mock response according to the different requests:
PS: Due to lack of documentation and sample scripts on this, I spent me several hours to do some investigation on it, the only thing to do is "reading the APIs and have a try".
Hope it helps,And Thanks for Lynn and Vance's help on this as well! :)
If you want to manage your mock response dispatch more flexible, then the Script way is your choice.
Here is the sample script you can select your mock response according to the different requests:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context);
def holder = groovyUtils.getXmlHolder(mockRequest.getRequestContent());
//Get node value from Xpath
def OID1 = holder.getNodeValue("//v2:getRequest[1]/v2:OIDs[1]");
def OID2 = holder.getNodeValue("//v2:getRequest[1]/v2:OIDs[2]");
//if condition 1 is matched, return mockresopnse1
if (OID1 == "C1308C7C-097F"&& OID2 == "") {
mockOperation.setDefaultResponse("mockresopnse1");
}
//else if condition 2 is matched, return mockresopnse2
else if (OID1 == "A097B4E5-0159" && OID2 == "17001212-AABF") {
mockOperation.setDefaultResponse("mockresopnse2");
}
PS: Due to lack of documentation and sample scripts on this, I spent me several hours to do some investigation on it, the only thing to do is "reading the APIs and have a try".
Hope it helps,And Thanks for Lynn and Vance's help on this as well! :)
Tuesday, May 25, 2010
Bad response on Firefox with enabling Gzip
While functional testing with enabling gzip(We are using Apache/2.0.49) bring me a bad news, there is randomly returns bad response instead of 200 or 304 response code with Firefox/3.6.3:

Apache access.log has indicated the .css file return 304 Not modified, however, FF seems neither receive 304 response code successfully nor retrieve it from local cache. So the page looks wired.
Another issue is that the page will display the irrecognizable characters in its response, something like this:
Meanwhile, IE seems works fine. Does it mean its a Firefox issue? Or it is a Apache 2.0.* gzip issue? (As i did not see such issues reported by Apache 2.2 version)
After taking simple search, there are other people met the same problem as well:
http://forums.mozillazine.org/viewtopic.php?f=38&t=1121915&p=9413795#p9413795
I tried Apache2.2.10, but it seems preventing 304 Not modified response, which is a bug of apache:
https://issues.apache.org/bugzilla/show_bug.cgi?id=45023
Anyone met the similar issues? Any better solutions?
Apache access.log has indicated the .css file return 304 Not modified, however, FF seems neither receive 304 response code successfully nor retrieve it from local cache. So the page looks wired.
Another issue is that the page will display the irrecognizable characters in its response, something like this:
���������HTTP/1.1 200 OK Date: Tue, 25 May 2010 07:30:02 GMT Server: Apache/2.0.49 (Win32) DAV/2 mod_ssl/2.0.55 OpenSSL/0.9.8e mod_jk/1.2.15 X-Powered-By: Servlet 2.4; JBoss-4.0.4.GA (build: CVSTag=JBoss_4_0_4_GA date=200605151000)/Tomcat-5.5 Vary: Accept-Encoding Content-Encoding: gzip Keep-Alive: timeout=15, max=88 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html;charset=UTF-8 a ¬� ������2d3 �VQo...
Meanwhile, IE seems works fine. Does it mean its a Firefox issue? Or it is a Apache 2.0.* gzip issue? (As i did not see such issues reported by Apache 2.2 version)
After taking simple search, there are other people met the same problem as well:
http://forums.mozillazine.org/viewtopic.php?f=38&t=1121915&p=9413795#p9413795
I tried Apache2.2.10, but it seems preventing 304 Not modified response, which is a bug of apache:
https://issues.apache.org/bugzilla/show_bug.cgi?id=45023
Anyone met the similar issues? Any better solutions?
Friday, May 21, 2010
"Firewall(?)" blocks "Accept-Encoding" header
recently, I did Gzip testing with loadrunner with "Accept-Encoding: gzip, deflate" request headers, so want to make sure that Gzip rocks as i told to my teammates.
My test scenario is running from remote server which located in US DC, it sent requests to China servers.
However, i noticed the test result is not changed, then i doubt about Gzip impact, keep look at apache access logs by adding \"%{Accept-Encoding}i\" to LogFormat in httpd.conf. There is no "gzip, deflate" header in access log found:
Then I did another round of test from local desktop, then everything is fine:
So "Firewall" blocks "Accept-Encoding" header is just my assumption, but not quite sure... At least notice your test result is making sense, otherwise, you are wasting of time, do not let such test result misleading!
Update:
Find a person with similar issue as mine: http://forums.mozillazine.org/viewtopic.php?f=9&t=1483185
There is Outpost Firewall which disable gzip...
Another latest post on "pushing beyond Gzipping" by Yahoo! talking about forcing Gzip when Accept-Encoding request header is mangled or stripped.
My test scenario is running from remote server which located in US DC, it sent requests to China servers.
However, i noticed the test result is not changed, then i doubt about Gzip impact, keep look at apache access logs by adding \"%{Accept-Encoding}i\" to LogFormat in httpd.conf. There is no "gzip, deflate" header in access log found:
"GET / HTTP/1.1" 200 2788 0 "-" "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1)" "-"
Then I did another round of test from local desktop, then everything is fine:
"GET / HTTP/1.1" 200 2788 0 "-" "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1)" "gzip, deflate"
So "Firewall" blocks "Accept-Encoding" header is just my assumption, but not quite sure... At least notice your test result is making sense, otherwise, you are wasting of time, do not let such test result misleading!
Update:
Find a person with similar issue as mine: http://forums.mozillazine.org/viewtopic.php?f=9&t=1483185
There is Outpost Firewall which disable gzip...
Another latest post on "pushing beyond Gzipping" by Yahoo! talking about forcing Gzip when Accept-Encoding request header is mangled or stripped.
Wednesday, May 12, 2010
Simple Performance profiling samples by Btrace
If you want to dig into why certain method runs slow than you expected, then you can do performance profiling by Btrace, Here is some simple example i used before, hope this helps, BTW, I used JVisualVM Btrace plugin, it is really easy of use, but Be caution with bugs :)
Calculate method execution time:
------------------------------------------------------------
Execution time between code lines:
PS: it calculates from code line 97 to 100 , but not including 100 execution time itself
--------------------------------------------------------------
Call dump trace:
-----------------------------------------------------------
Regular expression match on Clazz:
Calculate method execution time:
/* BTrace Script Template */
package com.sun.btrace.samples;
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.aggregation.*;
@BTrace
public class MethodResponseTime {
/* put your code here */
@TLS
private static long starttime;
private static Aggregation average = newAggregation(AggregationFunction.AVERAGE);
private static Aggregation globalcount = newAggregation(AggregationFunction.COUNT);
@OnMethod(
clazz = "com.myapp.service.pipeline.PipelineServlet",
method = "execute"
)
public static void onCall(){
println("enter this method!");
starttime = timeNanos();
}
@OnMethod(
clazz = "com.myapp.operations.PrePopulateResponse",
method = "execute",
location = @Location(Kind.RETURN)
)
public static void onReturn(){
println("Method End!");
int duration = (int)(timeNanos()- starttime)/1000000;
println(duration);
addToAggregation(average,duration);
addToAggregation(globalcount,duration);
}
@OnTimer(20000)
public static void onEvent(){
println("----------------");
printAggregation("Average", average);
printAggregation("Global Count", globalcount);
println("----------------");
}
}
------------------------------------------------------------
Execution time between code lines:
/* BTrace Script Template */
package com.sun.btrace.samples;
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.aggregation.*;
@BTrace
public class CodeLines {
@TLS private static long startTime;
@OnMethod(
clazz="com.myapp.impl.CommonResourceChangePollingImpl",
location=@Location(value=Kind.LINE, line=97)
)
public static void onEnter(){
//println("enter this method");
startTime= timeNanos();
}
@OnMethod(
clazz="com.myapp.impl.CommonResourceChangePollingImpl",
location=@Location(value=Kind.LINE, line=100)
)
public static void onReturn(){
//println("method end!");
int duration = (int)(timeNanos()-startTime)/1000000;
println(duration);
addToAggregation(average,duration);
addToAggregation(globalCount, duration);
}
@OnTimer(30000)
public static void onEvent() {
println("---------------------------------------------");
printAggregation("Average", average);
printAggregation("Global Count", globalCount);
println("---------------------------------------------");
}
}
PS: it calculates from code line 97 to 100 , but not including 100 execution time itself
--------------------------------------------------------------
Call dump trace:
/* BTrace Script Template */
package com.sun.btrace.samples;
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.aggregation.*;
@BTrace
public class CallTree {
@OnMethod(
clazz="com.myapp.impl.CommonResourceChangePollingImpl",
method="getResourceChanges",
location=@Location(value=Kind.LINE, line=-1)
)
public static void online(@ProbeClassName String pcn, @ProbeMethodName String pmn, int line) {
print(strcat(pcn, "."));
print(strcat(pmn, ":"));
println(line);
}
}
-----------------------------------------------------------
Regular expression match on Clazz:
/* BTrace Script Template */
package com.sun.btrace.samples;
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.aggregation.*;
@BTrace
public class RegexMatch {
@OnMethod(
clazz="/com\\.mycompany\\.service\\..*/",
location=@Location(value=Kind.LINE, line=-1)
)
public static void online(@ProbeClassName String pcn, @ProbeMethodName String pmn, int line) {
print(strcat(pcn, "."));
print(strcat(pmn, ":"));
println(line);
}
}
Monday, May 10, 2010
Create short URL by tinyurl service
Google charts usually create a long url which is really meaningless for us to read. and I want to convert by some external services instead of creating a new one, I tried Shorturl but failed due to network service problem or something.
here is one simple way to generate using http://tinyurl.com/ service, easy of use :)
Sample OUTPUT:
>>http://tinyurl.com/1c2
Note: If you did not encoding/escape the URL, then the service will call it "bad URI(is not URI?)...URI::InvalidURIError"
here is one simple way to generate using http://tinyurl.com/ service, easy of use :)
require 'open-uri'
require 'uri'
retrun_URL = 'http://chart.apis.google.com/chart?chxl=0:|load+google+landing+page|click_suggestion|1:|0|1|2|3|4|5&chxt=x,y&chco=76A4FB&chd=s:94&chtt=Detail+Page+Response+Time+for+GoogleSuggest.html&cht=lc&chs=900x300&chxr=1,5.977,5.401'
encoding_url = URI.escape(retrun_URL, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
tiny_url = open("http://tinyurl.com/api-create.php?url=#{encoding_url}").read
puts tiny_url
Sample OUTPUT:
>>http://tinyurl.com/1c2
Note: If you did not encoding/escape the URL, then the service will call it "bad URI(is not URI?)...URI::InvalidURIError"
Friday, May 07, 2010
Class loading issue by using Jaxb
After Monitoring our JVM by Jconsole/JvisalVM, I found the Perm Gen is not that stable and will perform Full GC after a short interval, meanwhile, the trend of total class loaded number is going up almost linear...
However Jconsole/JvisalVM only give me a rough idea that we got a problem on class loading or we just guess we may "dynamically creating new classes on the fly".


The simplest way to retrieve class loading information is to check the Verbose output check-box on Jconsole, so that you can trace the class loading event on command window where you started your service.

Here is some of loaded class information which caused the trouble we identify, Each new JAXB context would dynamically generate new classes instead of reusing the existing one:
Here is one potential solution on this similar problem, you can try that:
http://fleets.wordpress.com/2010/01/08/jaxb-memory-leak-with-metro-too-many-loaded-classes/
And also in HornetQ performance tuning " Avoiding Anti-Patterns", the first item is that "Re-use connections / sessions / consumers / producers", so we should Always re-use them instead of create new one. And also you could add -XX:+TraceClassLoading and -XX:+TraceClassUnloading for your running production to trace those information instead.
However Jconsole/JvisalVM only give me a rough idea that we got a problem on class loading or we just guess we may "dynamically creating new classes on the fly".
The simplest way to retrieve class loading information is to check the Verbose output check-box on Jconsole, so that you can trace the class loading event on command window where you started your service.
Here is some of loaded class information which caused the trouble we identify, Each new JAXB context would dynamically generate new classes instead of reusing the existing one:
[Loaded com.whatever.v2_0.RespondedDateRangeSummary$JaxbAccessor
F_responseOID from __JVM_DefineClass__]
[Loaded com.whatever.v2_0.RespondedDateRangeSummary$JaxbAccessor
F_respondDate from __JVM_DefineClass__]
[Loaded com.whatever.v2_0.RespondedDateRangeSummary$JaxbAccessor
F_respondDate from __JVM_DefineClass__]
[Loaded com.whatever.v2_0.RespondedDateRangeSummary$JaxbAccessor
F_statusRespondDate from __JVM_DefineClass__]
[Loaded com.whatever.v2_0.RespondedDateRangeSummary$JaxbAccessor
F_statusRespondDate from __JVM_DefineClass__]
[Loaded com.whatever.v2_0.RespondedDateRangeSummary$JaxbAccessor
F_statusOID from __JVM_DefineClass__]
[Loaded com.whatever.v2_0.RespondedDateRangeSummary$JaxbAccessor
F_statusOID from __JVM_DefineClass__]
[Loaded com.whatever.v2_0.RespondedDateRangeSummary$JaxbAccessor
F_statusCode from __JVM_DefineClass__]
[Loaded com.whatever.v2_0.RespondedDateRangeSummary$JaxbAccessor
F_statusCode from __JVM_DefineClass__]
Here is one potential solution on this similar problem, you can try that:
http://fleets.wordpress.com/2010/01/08/jaxb-memory-leak-with-metro-too-many-loaded-classes/
And also in HornetQ performance tuning " Avoiding Anti-Patterns", the first item is that "Re-use connections / sessions / consumers / producers", so we should Always re-use them instead of create new one. And also you could add -XX:+TraceClassLoading and -XX:+TraceClassUnloading for your running production to trace those information instead.
Subscribe to:
Posts (Atom)