Tag Archives: Unit Test

Stress Testing with WebORB

Yesterday and today I worked on a performance issue where 350 candidates had to wait more than a minute before their data was loaded. The 350 candidates start their exam simultaenously so the server is heavily loaded at that time. I had a couple of ideas in mind like caching certain things but how was I going to test this. I haven’t got 350 computers at my desk, I just have one laptop (and a development server).

A first tool I got from an answer on StackOverflow. AB is a tool for benchmarking apache server, but it can be used to benchmark any url(in my case local IIS). To do this I created an aspx page that loaded the same data that was loaded by one candidate. I then used AB to call that page multiple times. With this tool I already got a good idea how good my caching was working but I didn’t know if WebORB was also causing performance problems.

Since the last update we put on the development server of the customer, candidates had to wait much longer to get started. My guess was that it had to do with WebORB authentication. I now had to find a way to test my services by using the WebORB gateway. Asynchronous Unit Testing with FlexUnit had to be one of the answers. So I got started and two hours later I had my test. I did however had to try three different things.

In the first try I created a Test and added it a hundred times to the TestSuite. This wasn’t so usefull because the next Test starts only if the previous had ended. I needed simulteanously remote calls, parallel, not serial.

In the second try I created a Test that does a remote call a hundred times and is added only once to the TestSuite. This second try looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package {
	import flexunit.framework.Assert;
	import flexunit.framework.TestCase;
 
	import mx.rpc.AsyncToken;
	import mx.rpc.Fault;
	import mx.rpc.IResponder;
	import mx.rpc.Responder;
	import mx.rpc.remoting.mxml.RemoteObject;
 
	public class LoadExamSessionTest extends TestCase  {
 
		private var remoteObject:RemoteObject;
 
		override public function setUp():void {
			remoteObject = new RemoteObject("GenericDestination");
			remoteObject.source = "Edu3.ApplicationTestServices.LoadExamSessionBenchMarkTestService";
			remoteObject.endpoint = "http://localhost/edumatic3/local/weborb.aspx";
			// This is needed because the weborb authentication is enabled on the server side.
			remoteObject.setCredentials("credentials", "credentials");
 
		}
 
		public function testLoadExamSessionTest():void {
			for(var i:int ; i < 200 ; i++){			
				loadExamSession();
			}
		}
 
		public function loadExamSession():void{
			var token:AsyncToken = remoteObject.LoadTest();
			var responder:IResponder = new Responder
			(
				addAsync(onLoadExamSessionResult, 1000000), 
				null
			);
			token.addResponder(responder);
		}
 
		public function onLoadExamSessionResult(data:Object):void {
			assertNotNull(data.result);
		}
	}
}

This worked like a charm, but Authentication on the server side is only done once with the frist call because I’m using the same Remote Object every time. You should also check Charles to see what happens because it’s very interesting. Apparently the there are only two calls to weborb.aspx. The first call is the one that will trigger my custom authentication handler, the next call has packages 199 calls to the service… I won’t put a screenshot here because testing it is so much cooler. You can actually see in Charles that the server has started 199 threads and you can follow how much of the amf package is downloaded.

But this wasn’t what I needed because all 350 candidates are authenticated seperately. To simulate this I just create a new remote object for each call. Class now looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package {
	import flexunit.framework.Assert;
	import flexunit.framework.TestCase;
 
	import mx.rpc.AsyncToken;
	import mx.rpc.Fault;
	import mx.rpc.IResponder;
	import mx.rpc.Responder;
	import mx.rpc.remoting.mxml.RemoteObject;
 
	public class LoadExamSessionTest extends TestCase  {
 
		private var remoteObject:RemoteObject;
 
		override public function setUp():void {
		}
 
		public function testLoadExamSessionTest():void {
			for(var i:int ; i < 200 ; i++)
			{			
				loadExamSession();
			}
		}
 
		public function loadExamSession():void{
			remoteObject = new RemoteObject("GenericDestination");
			remoteObject.source = "Edu3.ApplicationTestServices.LoadExamSessionBenchMarkTestService";
			remoteObject.endpoint = "http://localhost/edumatic3/local/weborb.aspx";
			// This is needed because the weborb authentication is still enabled on the server side.
			remoteObject.setCredentials("credentials", "credentials");
 
			var token:AsyncToken = remoteObject.LoadTest();
			var responder:IResponder = new Responder
			(
				addAsync(onLoadExamSessionResult, 1000000), 
				null
			);
			token.addResponder(responder);
		}
 
		public function onLoadExamSessionResult(data:Object):void {
			assertNotNull(data.result);
		}
	}
}

Now you’ll see 200 calls to weborb.aspx in Charles and my custom WebORB authentication handler will be called 200 times. This is somewhat the customers case I wanted to simulate.

What did I find out, well, for 200 remote calls, the third scenario (200 times weborb authentication) takes double as long as the second scenario (once weborb authentication).

The Caching on the server times now speeds up the loading of the data five times!

ps: I do need to dig in a little deeper in the addAsync from FlexUnit because when I add another addAsync for my fault event in the Reponder, things get messy… Will keep you posted on this.

Ciao! Lieven Cardoen aka Johlero